Aracılığıyla paylaş


İlişki bulma kuralları

EF Core, varlık türü sınıflarını temel alan bir model keşfederken ve oluştururken bir dizi kural kullanır. Bu belge, varlık türleri arasındaki ilişkileri bulmak ve yapılandırmak için kullanılan kuralları özetler.

Önemli

Burada açıklanan kurallar, eşleme öznitelikleri veya model oluşturma API'si kullanılarak ilişkinin açık yapılandırmasıyla geçersiz kılınabilir.

Bahşiş

Aşağıdaki kod RelationshipConventions.cs içinde bulunabilir.

Gezintileri bulma

İlişki bulma, varlık türleri arasındaki gezintileri bularak başlar.

Başvuru gezintileri

Bir varlık türünün özelliği aşağıdaki durumlarda başvuru gezintisi olarak bulunur:

  • özelliği geneldir.
  • özelliğinde bir alıcı ve ayarlayıcı vardır.
  • Özellik türü bir varlık türüdür veya olabilir. Bu, türün
    • Bir başvuru türü olmalıdır.
    • İlkel özellik türü olarak açıkça yapılandırılmamış olmalıdır.
    • Kullanılan veritabanı sağlayıcısı tarafından ilkel özellik türü olarak eşlenmemelidir.
    • Kullanılan veritabanı sağlayıcısı tarafından eşlenen ilkel özellik türüne otomatik olarak dönüştürülemez.
  • Özelliği statik değil.
  • özelliği bir dizin oluşturucu özelliği değildir.

Örneğin, aşağıdaki varlık türlerini göz önünde bulundurun:

public class Blog
{
    // Not discovered as reference navigations:
    public int Id { get; set; }
    public string Title { get; set; } = null!;
    public Uri? Uri { get; set; }
    public ConsoleKeyInfo ConsoleKeyInfo { get; set; }
    public Author DefaultAuthor => new() { Name = $"Author of the blog {Title}" };

    // Discovered as a reference navigation:
    public Author? Author { get; private set; }
}

public class Author
{
    // Not discovered as reference navigations:
    public Guid Id { get; set; }
    public string Name { get; set; } = null!;
    public int BlogId { get; set; }

    // Discovered as a reference navigation:
    public Blog Blog { get; init; } = null!;
}

Bu türler Blog.Author için ve Author.Blog başvuru gezintileri olarak bulunur. Öte yandan, aşağıdaki özellikler başvuru gezintileri olarak bulunmaz :

  • Blog.Id, çünkü int eşlenmiş bir ilkel türdür
  • Blog.Title, çünkü 'string' eşlenmiş bir ilkel türdür
  • Blog.Uri, çünkü Uri otomatik olarak eşlenmiş ilkel türe dönüştürülür
  • Blog.ConsoleKeyInfo, çünkü ConsoleKeyInfo bir C# değer türüdür
  • Blog.DefaultAuthor, özelliğinde ayarlayıcı olmadığından
  • Author.Id, çünkü Guid eşlenmiş bir ilkel türdür
  • Author.Name, çünkü 'string' eşlenmiş bir ilkel türdür
  • Author.BlogId, çünkü int eşlenmiş bir ilkel türdür

Koleksiyon gezintileri

Bir varlık türünün özelliği, şu durumlarda koleksiyon gezintisi olarak bulunur:

  • özelliği geneldir.
  • Özelliğin alıcısı vardır. Koleksiyon gezintilerinde ayarlayıcılar olabilir, ancak bu gerekli değildir.
  • Özellik türü, bir varlık türü olduğu veya olabileceği veya TEntity olabileceği şeklindedir veya uygularIEnumerable<TEntity>. Bu, türü TEntityanlamına gelir:
    • Bir başvuru türü olmalıdır.
    • İlkel özellik türü olarak açıkça yapılandırılmamış olmalıdır.
    • Kullanılan veritabanı sağlayıcısı tarafından ilkel özellik türü olarak eşlenmemelidir.
    • Kullanılan veritabanı sağlayıcısı tarafından eşlenen ilkel özellik türüne otomatik olarak dönüştürülemez.
  • Özelliği statik değil.
  • özelliği bir dizin oluşturucu özelliği değildir.

Örneğin, aşağıdaki kodda hem hem Tag.Blogs de Blog.Tags koleksiyon gezintileri olarak bulunur:

public class Blog
{
    public int Id { get; set; }
    public List<Tag> Tags { get; set; } = null!;
}

public class Tag
{
    public Guid Id { get; set; }
    public IEnumerable<Blog> Blogs { get; } = new List<Blog>();
}

Gezintileri eşleştirme

Örneğin, A varlık türünden B varlık türüne giden bir gezinti bulunduktan sonra, bu gezintinin ters yönde giden bir ters yönü olup olmadığının (yani B varlık türünden A varlık türüne) belirlenmesi gerekir. Böyle bir ters bulunursa, iki gezinti tek bir çift yönlü ilişki oluşturmak için birlikte eşleştirilir.

İlişki türü, gezintinin ve tersinin başvuru mu yoksa koleksiyon gezintileri mi olduğuna göre belirlenir. Özellikle:

  • Gezintilerden biri koleksiyon gezintisi, diğeri başvuru gezintisi ise ilişki bire çok şeklindedir.
  • Her iki gezinti de başvuru gezintileriyse ilişki bire bir olur.
  • Her iki gezinti de koleksiyon gezintileriyse ilişki çoka çok olur.

Bu ilişki türlerinin her birinin bulunması aşağıdaki örneklerde gösterilmiştir:

ile arasında Blog Post ve gezintileri eşleştirilerek Blog.Posts Post.Blog tek, bire çok ilişkisi bulunur:

public class Blog
{
    public int Id { get; set; }
    public ICollection<Post> Posts { get; } = new List<Post>();
}

public class Post
{
    public int Id { get; set; }
    public int? BlogId { get; set; }
    public Blog? Blog { get; set; }
}

ile arasında Blog bire bir ilişki bulunur ve Author ile gezintileri eşleştirilerek Blog.Author Author.Blog bulunur:

public class Blog
{
    public int Id { get; set; }
    public Author? Author { get; set; }
}

public class Author
{
    public int Id { get; set; }
    public int? BlogId { get; set; }
    public Blog? Blog { get; set; }
}

ile arasında Post Tag ve gezintileri eşleştirilerek Post.Tags Tag.Posts tek, çoka çok ilişkisi bulunur:

public class Post
{
    public int Id { get; set; }
    public ICollection<Tag> Tags { get; } = new List<Tag>();
}

public class Tag
{
    public int Id { get; set; }
    public ICollection<Post> Posts { get; } = new List<Post>();
}

Dekont

İki gezinti iki farklı, tek yönlü ilişkiyi temsil ederse, bu gezinti eşleştirmesi yanlış olabilir. Bu durumda, iki ilişki açıkça yapılandırılmalıdır.

İlişkilerin eşlenmesi yalnızca iki tür arasında tek bir ilişki olduğunda çalışır. İki tür arasındaki birden çok ilişki açıkça yapılandırılmalıdır.

Dekont

Buradaki açıklamalar iki farklı tür arasındaki ilişkiler açısındandır. Ancak, aynı türün bir ilişkinin her iki ucunda olması ve bu nedenle tek bir türün her ikisi de birbiriyle eşleştirilmiş iki gezintiye sahip olması mümkündür. Buna kendi kendine başvuran ilişki denir.

Yabancı anahtar özelliklerini bulma

bir ilişkinin gezintileri keşfedildikten veya açıkça yapılandırıldıktan sonra, bu gezintiler ilişki için uygun yabancı anahtar özelliklerini bulmak için kullanılır. Bir özellik şu durumlarda yabancı anahtar olarak bulunur:

  • Özellik türü, asıl varlık türündeki birincil veya alternatif anahtarla uyumludur.
    • Türler aynıysa veya yabancı anahtar özellik türü birincil veya alternatif anahtar özellik türünün null atanabilir bir sürümüyse uyumludur.
  • Özellik adı, yabancı anahtar özelliği için adlandırma kurallarından biriyle eşleşir. Adlandırma kuralları şunlardır:
    • <navigation property name><principal key property name>
    • <navigation property name>Id
    • <principal entity type name><principal key property name>
    • <principal entity type name>Id
  • Ayrıca, bağımlı uç model oluşturma API'sini kullanarak açıkça yapılandırıldıysa ve bağımlı birincil anahtar uyumluysa, bağımlı birincil anahtar yabancı anahtar olarak da kullanılır.

Bahşiş

"Kimlik" soneki herhangi bir büyük/küçük harf içerebilir.

Aşağıdaki varlık türleri, bu adlandırma kurallarının her biri için örnekler gösterir.

Post.TheBlogKey , deseniyle <navigation property name><principal key property name>eşleştiğinden yabancı anahtar olarak bulunur:

public class Blog
{
    public int Key { get; set; }
    public ICollection<Post> Posts { get; } = new List<Post>();
}

public class Post
{
    public int Id { get; set; }
    public int? TheBlogKey { get; set; }
    public Blog? TheBlog { get; set; }
}

Post.TheBlogID , deseniyle <navigation property name>Ideşleştiğinden yabancı anahtar olarak bulunur:

public class Blog
{
    public int Key { get; set; }
    public ICollection<Post> Posts { get; } = new List<Post>();
}

public class Post
{
    public int Id { get; set; }
    public int? TheBlogID { get; set; }
    public Blog? TheBlog { get; set; }
}

Post.BlogKey , deseniyle <principal entity type name><principal key property name>eşleştiğinden yabancı anahtar olarak bulunur:

public class Blog
{
    public int Key { get; set; }
    public ICollection<Post> Posts { get; } = new List<Post>();
}

public class Post
{
    public int Id { get; set; }
    public int? BlogKey { get; set; }
    public Blog? TheBlog { get; set; }
}

Post.Blogid , deseniyle <principal entity type name>Ideşleştiğinden yabancı anahtar olarak bulunur:

public class Blog
{
    public int Key { get; set; }
    public ICollection<Post> Posts { get; } = new List<Post>();
}

public class Post
{
    public int Id { get; set; }
    public int? Blogid { get; set; }
    public Blog? TheBlog { get; set; }
}

Dekont

Bire çok gezintiler söz konusu olduğunda, yabancı anahtar özellikleri başvuru gezintisi ile türünde olmalıdır, çünkü bu bağımlı varlık olacaktır. Bire bir ilişkiler söz konusu olduğunda, ilişkinin bağımlı sonunu temsil eden türü belirlemek için yabancı anahtar özelliğinin bulunması kullanılır. Yabancı anahtar özelliği bulunmazsa, bağımlı uç kullanılarak HasForeignKeyyapılandırılmalıdır. Bunun örnekleri için bkz . Bire bir ilişkiler .

Yukarıdaki kurallar bileşik yabancı anahtarlar için de geçerlidir; burada bileşik özelliğin her özelliği birincil veya alternatif anahtarın ilgili özelliğiyle uyumlu bir türe sahip olmalıdır ve her özellik adı yukarıda açıklanan adlandırma kurallarından biriyle eşleşmelidir.

Kardinaliteyi belirleme

EF, ilişki kardinalitesini asıl ve bağımlı uçlarıyla birlikte belirlemek için bulunan gezintileri ve yabancı anahtar özelliklerini kullanır:

  • Eşleşmeyen bir başvuru gezintisi varsa, ilişki tek yönlü bire çok olarak yapılandırılır ve başvuru gezintisi bağımlı uçta olur.
  • Eşleşmeyen bir koleksiyon gezintisi varsa, ilişki tek yönlü bire çok olarak yapılandırılır ve asıl uçta koleksiyon gezintisi bulunur.
  • Eşleştirilmiş başvuru ve koleksiyon gezintileri varsa, ilişki çift yönlü bire çok olarak yapılandırılır ve koleksiyon gezintisi asıl uçta olur.
  • Başvuru gezintisi başka bir başvuru gezintisi ile eşleştirilmişse:
    • Yabancı anahtar özelliği bir tarafta bulunur ancak diğer tarafında bulunmazsa, ilişki bağımlı uçta yabancı anahtar özelliğiyle bire bir çift yönlü olarak yapılandırılır.
    • Aksi takdirde, bağımlı taraf belirlenemez ve EF, bağımlının açıkça yapılandırılması gerektiğini belirten bir özel durum oluşturur.
  • Koleksiyon gezintisi başka bir koleksiyon gezintisi ile eşleştirilirse, ilişki çift yönlü çoka çok olarak yapılandırılır.

Gölge yabancı anahtar özellikleri

EF ilişkinin bağımlı sonunu belirlediyse ancak yabancı anahtar özelliği bulunamadıysa, EF yabancı anahtarı temsil eden bir gölge özellik oluşturur. Gölge özelliği:

  • İlişkinin asıl ucunda birincil veya alternatif anahtar özelliğinin türüne sahiptir.
    • Tür varsayılan olarak null atanabilir hale getirilerek ilişki varsayılan olarak isteğe bağlıdır.
  • Bağımlı uçta bir gezinti varsa, gölge yabancı anahtar özelliği birincil veya alternatif anahtar özelliği adıyla birleştirilmiş bu gezinti adı kullanılarak adlandırılır.
  • Bağımlı uçta gezinti yoksa, birincil veya alternatif anahtar özelliği adıyla birleştirilmiş asıl varlık türü adı kullanılarak gölge yabancı anahtar özelliği adlandırılır.

Basamaklı silme

Kural gereği, gerekli ilişkiler art arda silmek üzere yapılandırılır. İsteğe bağlı ilişkiler art arda silinmeyecek şekilde yapılandırılır.

Çok-çok

Çoka çok ilişkilerin asıl ve bağımlı uçları yoktur ve hiçbir uç bir yabancı anahtar özelliği içermez. Bunun yerine, çoka çok ilişkiler, çoka çok'un iki ucuna işaret eden yabancı anahtar çiftleri içeren bir birleştirme varlık türü kullanır. Kural tarafından çoka çok ilişkisinin bulunduğu aşağıdaki varlık türlerini göz önünde bulundurun:

public class Post
{
    public int Id { get; set; }
    public ICollection<Tag> Tags { get; } = new List<Tag>();
}

public class Tag
{
    public int Id { get; set; }
    public ICollection<Post> Posts { get; } = new List<Post>();
}

Bu keşifte kullanılan kurallar şunlardır:

  • Birleştirme varlık türü olarak adlandırılır <left entity type name><right entity type name>. PostTag Bu örnekte.
    • Birleştirme tablosu birleştirme varlık türüyle aynı ada sahiptir.
  • Birleştirme varlık türüne ilişkinin her yönü için bir yabancı anahtar özelliği verilir. Bunlar olarak adlandırılır <navigation name><principal key name>. Bu nedenle, bu örnekte yabancı anahtar özellikleri ve TagsIdşeklindedirPostsId.
    • Tek yönlü çoka çok için, ilişkili gezintisi olmayan yabancı anahtar özelliği olarak adlandırılır <principal entity type name><principal key name>.
  • Yabancı anahtar özellikleri null atanamaz, bu da birleştirme varlığıyla her iki ilişkiyi de gerekli hale getirir.
    • Art arda silme kuralları, bu ilişkilerin art arda silme için yapılandırılacağı anlamına gelir.
  • Birleştirme varlık türü, iki yabancı anahtar özelliğinden oluşan bileşik bir birincil anahtarla yapılandırılır. Bu nedenle, bu örnekte birincil anahtar ve TagsId'inden PostsId oluşur.

Bu, aşağıdaki EF modeline neden olur:

Model:
  EntityType: Post
    Properties:
      Id (int) Required PK AfterSave:Throw ValueGenerated.OnAdd
    Skip navigations:
      Tags (ICollection<Tag>) CollectionTag Inverse: Posts
    Keys:
      Id PK
  EntityType: Tag
    Properties:
      Id (int) Required PK AfterSave:Throw ValueGenerated.OnAdd
    Skip navigations:
      Posts (ICollection<Post>) CollectionPost Inverse: Tags
    Keys:
      Id PK
  EntityType: PostTag (Dictionary<string, object>) CLR Type: Dictionary<string, object>
    Properties:
      PostsId (no field, int) Indexer Required PK FK AfterSave:Throw
      TagsId (no field, int) Indexer Required PK FK Index AfterSave:Throw
    Keys:
      PostsId, TagsId PK
    Foreign keys:
      PostTag (Dictionary<string, object>) {'PostsId'} -> Post {'Id'} Cascade
      PostTag (Dictionary<string, object>) {'TagsId'} -> Tag {'Id'} Cascade
    Indexes:
      TagsId

Ve SQLite kullanılırken aşağıdaki veritabanı şemasına çevrilir:

CREATE TABLE "Posts" (
    "Id" INTEGER NOT NULL CONSTRAINT "PK_Posts" PRIMARY KEY AUTOINCREMENT);

CREATE TABLE "Tag" (
    "Id" INTEGER NOT NULL CONSTRAINT "PK_Tag" PRIMARY KEY AUTOINCREMENT);

CREATE TABLE "PostTag" (
    "PostsId" INTEGER NOT NULL,
    "TagsId" INTEGER NOT NULL,
    CONSTRAINT "PK_PostTag" PRIMARY KEY ("PostsId", "TagsId"),
    CONSTRAINT "FK_PostTag_Posts_PostsId" FOREIGN KEY ("PostsId") REFERENCES "Posts" ("Id") ON DELETE CASCADE,
    CONSTRAINT "FK_PostTag_Tag_TagsId" FOREIGN KEY ("TagsId") REFERENCES "Tag" ("Id") ON DELETE CASCADE);

CREATE INDEX "IX_PostTag_TagsId" ON "PostTag" ("TagsId");

Dizinler

Kural gereği EF, yabancı anahtarın özelliği veya özellikleri için bir veritabanı dizini oluşturur. Oluşturulan dizinin türü şu şekilde belirlenir:

  • İlişkinin kardinalitesi
  • İlişkinin isteğe bağlı mı yoksa gerekli mi olduğu
  • Yabancı anahtarı oluşturan özelliklerin sayısı

Bire çok ilişkisi için kural tarafından basit bir dizin oluşturulur. İsteğe bağlı ve gerekli ilişkiler için aynı dizin oluşturulur. Örneğin, SQLite üzerinde:

CREATE INDEX "IX_Post_BlogId" ON "Post" ("BlogId");

Veya SQL Server'da:

CREATE INDEX [IX_Post_BlogId] ON [Post] ([BlogId]);

Gerekli bire bir ilişki için benzersiz bir dizin oluşturulur. Örneğin, SQLite üzerinde:

CREATE UNIQUE INDEX "IX_Author_BlogId" ON "Author" ("BlogId");

Veya SQL Sever'de:

CREATE UNIQUE INDEX [IX_Author_BlogId] ON [Author] ([BlogId]);

İsteğe bağlı bire bir ilişkiler için SQLite'te oluşturulan dizin aynıdır:

CREATE UNIQUE INDEX "IX_Author_BlogId" ON "Author" ("BlogId");

Ancak SQL Server'da null yabancı anahtar değerlerini daha iyi işlemek için bir IS NOT NULL filtre eklenir. Örnek:

CREATE UNIQUE INDEX [IX_Author_BlogId] ON [Author] ([BlogId]) WHERE [BlogId] IS NOT NULL;

Bileşik yabancı anahtarlar için, tüm yabancı anahtar sütunlarını kapsayan bir dizin oluşturulur. Örnek:

CREATE INDEX "IX_Post_ContainingBlogId1_ContainingBlogId2" ON "Post" ("ContainingBlogId1", "ContainingBlogId2");

Dekont

EF, zaten var olan bir dizin veya birincil anahtar kısıtlaması kapsamında olan özellikler için dizin oluşturmaz.

EF'nin yabancı anahtarlar için dizin oluşturmasını durdurma

Dizinlerin ek yükü vardır ve burada istendiği gibi, bunları tüm FK sütunları için oluşturmak her zaman uygun olmayabilir. Bunu başarmak için, ForeignKeyIndexConvention modeli oluştururken kaldırılabilir:

protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
{
    configurationBuilder.Conventions.Remove(typeof(ForeignKeyIndexConvention));
}

İstendiğinde, dizinler yine de bunlara ihtiyaç duyan yabancı anahtar sütunları için açıkça oluşturulabilir .

Yabancı anahtar kısıtlama adları

Kurala göre yabancı anahtar kısıtlamaları olarak adlandırılır FK_<dependent type name>_<principal type name>_<foreign key property name>. Bileşik yabancı anahtarlar için, <foreign key property name> yabancı anahtar özellik adlarının alt çizgiyle ayrılmış listesi haline gelir.

Ek kaynaklar