İlişki bulma ilkeleri

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.

Tavsiye

Kod aşağıda belirtilen RelationshipConventions.cs dosyasının içinde bulunabilir.

Gezintileri keşfetme

İlişki bulma, varlık türleri arasındaki yönlendirmeleri keşfederek başlar.

Referans gezintileri

Bir varlık türünün özelliği aşağıdaki koşullar altında referans yönlendirmesi olarak keşfedilir:

  • Mülk herkese açıktır.
  • Özellikte bir get fonksiyonu ve bir set fonksiyonu vardır.
    • Ayarlayıcının genel olması gerekmez; özel olabilir veya başka bir erişilebilirlik düzeyine sahip olabilir.
    • Ayarlayıcı yalnızca init olarak ayarlanabilir.
  • Özellik türü bir varlık türüdür veya olabilir. Bu, türün anlamına gelir
  • Ö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ürlerde, Blog.Author ve Author.Blog başvuru gezintileri olarak keşfedilir. Öte yandan, aşağıdaki özellikler referans 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:

  • Mülk herkese açıktır.
  • Özelliğin alıcısı vardır. Koleksiyon gezintilerinde ayarlayıcılar olabilir, ancak bu gerekli değildir.
  • Özellik türü IEnumerable<TEntity> veya TEntity uygulayabilir; burada, TEntity bir varlık türü olabilir veya varlık türü olabilir. Bu, TEntity türü anlamına gelir:
  • Özelliği statik değil.
  • özelliği bir dizin oluşturucu özelliği değildir.

Örneğin, aşağıdaki kodda hem Blog.Tags hem de Tag.Blogs koleksiyon gezinmesi 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>();
}

Yönlendirmeleri 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ü, navigasyonun ve karşıtının referans mı yoksa koleksiyon navigasyonu mu olduğuna göre belirlenir. Özellikle:

  • Gezintilerden biri koleksiyon gezintisi, diğeri başvuru gezintisi ise ilişki birden çoğa şeklindedir.
  • Her iki gezinti de referans gezintisi ise, ilişki bire bir olur.
  • Her iki navigasyon da koleksiyon navigasyonlarıysa ilişki çoka çok olarak tanımlanır.

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

Blog ile Post arasında tek, bire çok ilişki, Blog.Posts ve Post.Blog navigasyonları eşleştirilerek keşfedilir.

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; }
}

Blog ve Author arasındaki bire bir ilişki, Blog.Author ve Author.Blog navigasyonlarının eşleştirilmesiyle keşfedilir.

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; }
}

Tek bir, çoka çok ilişkisi Post ve Tag arasında, Post.Tags ve Tag.Posts yönlendirmeleri eşleştirilerek 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>();
}

Uyarı

İ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.

Uyarı

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 yer alması ve bu nedenle tek bir türün birbirine bağlı iki navigasyona sahip olması mümkündür. Bu, öz referanslı bir ilişki olarak adlandırılır.

Yabancı anahtar özelliklerini bulma

Bir ilişkinin navigasyonları belirlendikten veya belirgin şekilde yapılandırıldıktan sonra, bu navigasyonlar ilişki için uygun yabancı anahtar özelliklerini bulmak için kullanılır. Bir özellik şu durumlarda yabancı anahtar olarak tanımlanır:

  • Ö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.

Tavsiye

"Id" son eki herhangi bir büyük/küçük harf biçimine sahip olabilir.

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

Post.TheBlogKey, <navigation property name><principal key property name> deseniyle eşleştiği için yabancı anahtar olarak bulunmuştur.

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, <navigation property name>Id deseniyle eşleştiği için yabancı anahtar olarak bulunmuştur.

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, <principal entity type name><principal key property name> deseniyle eşleştiği için yabancı anahtar olarak bulunmuştur.

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, <principal entity type name>Id deseniyle eşleştiği için yabancı anahtar olarak bulunmuştur.

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; }
}

Uyarı

Bire çok gezinmeler söz konusu olduğunda, yabancı anahtar özellikleri referans gezinmeye sahip türde bulunmalıdır, çünkü bu tür bağımlı varlıktı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ç HasForeignKey kullanılarak yapı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 iki yönlü olarak yapılandırılır.
    • Aksi takdirde, bağımlı bileşen belirlenemez ve EF, bağımlının açıkça yapılandırılması gerektiğini belirten bir hata verir.
  • Koleksiyon gezintisi başka bir koleksiyon gezintisi ile eşleştirilirse, ilişki iki 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 olabilen hale getirilerek, ilişki varsayılan olarak isteğe bağlı hale gelir.
  • 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 gezinme yoksa, gölge yabancı anahtar özelliği, birincil veya alternatif anahtar özelliği adıyla birleştirilmiş asıl varlık türü adı kullanılarak 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 çiftlerini içeren bir ilişkisel varlık türü kullanır. Anlaşmaya göre çoka çok ilişkisi bulunan 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ünün adı <left entity type name><right entity type name> olarak belirlenmiştir. Yani, PostTag bu örnekte.
    • Birleştirme tablosu, birleştirme varlığı 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 PostsId ve TagsId'dir.
    • Tek yönlü çoka çok durumda, ilişkili gezintisi olmayan yabancı anahtar özelliğine <principal entity type name><principal key name> adı verilir.
  • Yabancı anahtar özellikleri null olamaz, bu da birleştirme varlığı ile her iki ilişkiyi zorunlu 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 PostsId ve TagsId'den 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 geleneksel olarak 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. Örneğin:

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. Örneğin:

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

Uyarı

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