İ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.
- Ayarlayıcının genel olması gerekmez; özel olabilir veya başka bir erişilebilirliği olabilir.
- Ayarlayıcı yalnızca init olabilir.
- Özellik türü bir varlık türüdür veya olabilir. Bu, türün
- Ö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ürBlog.Title
, çünkü 'string' eşlenmiş bir ilkel türdürBlog.Uri
, çünküUri
otomatik olarak eşlenmiş ilkel türe dönüştürülürBlog.ConsoleKeyInfo
, çünküConsoleKeyInfo
bir C# değer türüdürBlog.DefaultAuthor
, özelliğinde ayarlayıcı olmadığındanAuthor.Id
, çünküGuid
eşlenmiş bir ilkel türdürAuthor.Name
, çünkü 'string' eşlenmiş bir ilkel türdürAuthor.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üTEntity
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 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>Id
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? 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>Id
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? 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 HasForeignKey
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 ç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 veTagsId
ş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>
.
- Tek yönlü çoka çok için, ilişkili gezintisi olmayan yabancı anahtar özelliği olarak adlandırılır
- 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
'indenPostsId
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
- Özel model kurallarıyla ilgili .NET Veri Topluluğu Standup videosu.