Aracılığıyla paylaş


Bir-çok ilişkileri

Bire çok ilişkiler, tek bir varlık herhangi bir sayıda diğer varlıkla ilişkilendirildiğinde kullanılır. Örneğin, bir Blog ile ilişkili Postsbirçok olabilir, ancak her Post biri yalnızca bir Blogile ilişkilendirilir.

Bu belge birçok örnek etrafında yapılandırılmıştır. Örnekler, kavramların da tanıtıldığı yaygın durumlarla başlar. Sonraki örnekler daha az yaygın yapılandırma türlerini kapsar. Burada iyi bir yaklaşım, ilk birkaç örneği ve kavramı anlamak ve ardından özel gereksinimlerinize göre sonraki örneklere gitmektir. Bu yaklaşıma dayanarak, basit "gerekli" ve "isteğe bağlı" bire çok ilişkilerle başlayacağız.

İpucu

Aşağıdaki tüm örneklerin kodu OneToMany.cs bulunabilir.

Bire çok gerekli

// Principal (parent)
public class Blog
{
    public int Id { get; set; }
    public ICollection<Post> Posts { get; } = new List<Post>(); // Collection navigation containing dependents
}

// Dependent (child)
public class Post
{
    public int Id { get; set; }
    public int BlogId { get; set; } // Required foreign key property
    public Blog Blog { get; set; } = null!; // Required reference navigation to principal
}

Bire çok ilişkisi aşağıdakilerden oluşur:

  • Asıl varlıkta bir veya daha fazla birincil veya alternatif anahtar özelliği; yani ilişkinin "bir" ucudur. Örneğin, Blog.Id.
  • Bağımlı varlık üzerindeki bir veya daha fazla yabancı anahtar özelliği; yani ilişkinin "çok" sonudur. Örneğin, Post.BlogId.
  • İsteğe bağlı olarak, bağımlı varlıklara başvuran asıl varlıkta bir koleksiyon gezintisi . Örneğin, Blog.Posts.
  • İsteğe bağlı olarak, asıl varlığa başvuran bağımlı varlıkta bir başvuru gezintisi . Örneğin, Post.Blog.

Bu örnekteki ilişki için:

  • Yabancı anahtar özelliği Post.BlogId null atanamaz. Bu, yabancı anahtar özelliğinin bir değere ayarlanması gerektiğinden, her bağımlı () öğesinin bir sorumluyla (PostBlog ) ilişkili olması gerektiğinden ilişkiyi "gerekli" yapar.
  • Her iki varlığın da ilişkinin diğer tarafındaki ilgili varlığa veya varlıklara işaret eden gezintileri vardır.

Not

Gerekli bir ilişki, her bağımlı varlığın bir asıl varlıkla ilişkilendirilmesini sağlar. Ancak, bir asıl varlık her zaman bağımlı varlıklar olmadan var olabilir. Başka bir ifadeyle, gerekli bir ilişki her zaman en az bir bağımlı varlık olacağını göstermez. EF modelinde hiçbir yol yoktur ve ayrıca bir sorumlunun belirli sayıda bağımlıyla ilişkilendirildiğinden emin olmak için ilişkisel veritabanında standart bir yol yoktur. Bu gerekiyorsa, uygulama (iş) mantığında uygulanmalıdır. Daha fazla bilgi için bkz . Gerekli gezintiler .

İpucu

Biri bağımlıdan sorumluya, diğeri sorumludan bağımlılara olmak üzere iki gezinti içeren bir ilişki, çift yönlü ilişki olarak bilinir.

Bu ilişki kural tarafından bulunur. Bunun anlamı:

  • Blog ilişkide sorumlu olarak bulunur ve Post bağımlı olarak bulunur.
  • Post.BlogId , sorumlunun birincil anahtarına başvuran bağımlının Blog.Id yabancı anahtarı olarak bulunur. İlişki, null atanamaz olduğundan Post.BlogId gerektiği gibi bulunur.
  • Blog.Posts , koleksiyon gezintisi olarak bulunur.
  • Post.Blog , başvuru gezintisi olarak bulunur.

Önemli

C# null atanabilir başvuru türleri kullanılırken, yabancı anahtar özelliği null atanabilirse başvuru gezintisi null atanabilir olmalıdır. Yabancı anahtar özelliği null atanamazsa, başvuru gezintisi null atanabilir veya olamaz. Bu durumda, Post.BlogId null atanamaz ve Post.Blog aynı zamanda null atanamaz. Yapısı = null!; , bunu C# derleyicisi için kasıtlı olarak işaretlemek için kullanılır, çünkü EF genellikle örneği ayarlar Blog ve tam yüklü bir ilişki için null olamaz. Daha fazla bilgi için bkz . Null Atanabilir Başvuru Türleriyle Çalışma.

Gezintilerin, yabancı anahtarın veya ilişkinin gerekli/isteğe bağlı doğasının kurala göre keşfedilmediği durumlarda, bu öğeler açıkça yapılandırılabilir. Örneğin:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasMany(e => e.Posts)
        .WithOne(e => e.Blog)
        .HasForeignKey(e => e.BlogId)
        .IsRequired();
}

Yukarıdaki örnekte, ilişkilerin yapılandırması asıl varlık türünde (Blog) ile HasMany başlar ve bunu ile WithOneizler. Tüm ilişkilerde olduğu gibi, bağımlı varlık türüyle (Post) başlamak ve ardından WithManykullanmak HasOne tam olarak eşdeğerdir. Örneğin:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Post>()
        .HasOne(e => e.Blog)
        .WithMany(e => e.Posts)
        .HasForeignKey(e => e.BlogId)
        .IsRequired();
}

Bu seçeneklerin hiçbiri diğerinden daha iyi değildir; her ikisi de tam olarak aynı yapılandırmayla sonuçlanır.

İpucu

Hiçbir zaman bir ilişkiyi sorumludan başlayıp bağımlıdan başlayarak iki kez yapılandırmak gerekmez. Ayrıca, bir ilişkinin sorumlu ve bağımlı yarılarını ayrı ayrı yapılandırmaya çalışmak genellikle işe yaramaz. Her ilişkiyi bir uçtan veya diğerinden yapılandırmayı seçin ve yapılandırma kodunu yalnızca bir kez yazın.

İsteğe bağlı bire çok

// Principal (parent)
public class Blog
{
    public int Id { get; set; }
    public ICollection<Post> Posts { get; } = new List<Post>(); // Collection navigation containing dependents
}

// Dependent (child)
public class Post
{
    public int Id { get; set; }
    public int? BlogId { get; set; } // Optional foreign key property
    public Blog? Blog { get; set; } // Optional reference navigation to principal
}

Bu, önceki örnekle aynıdır, ancak yabancı anahtar özelliği ve sorumluya gezinti artık null atanabilir. Bir bağımlı () herhangi bir sorumluyla (PostBlog) ilgili olmadan var olabileceğinden, bu ilişkiyi "isteğe bağlı" yapar.

Önemli

C# null atanabilir başvuru türleri kullanılırken, yabancı anahtar özelliği null atanabilirse başvuru gezintisi null atanabilir olmalıdır. Bu durumda, Post.BlogId null atanabilir, bu nedenle Post.Blog de null atanabilir olmalıdır. Daha fazla bilgi için bkz . Null Atanabilir Başvuru Türleriyle Çalışma.

Daha önce olduğu gibi, bu ilişki kural tarafından bulunur. Gezintilerin, yabancı anahtarın veya ilişkinin gerekli/isteğe bağlı doğasının kurala göre keşfedilmediği durumlarda, bu öğeler açıkça yapılandırılabilir. Örneğin:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasMany(e => e.Posts)
        .WithOne(e => e.Blog)
        .HasForeignKey(e => e.BlogId)
        .IsRequired(false);
}

Gölge yabancı anahtarla bire çok gerekli

// Principal (parent)
public class Blog
{
    public int Id { get; set; }
    public ICollection<Post> Posts { get; } = new List<Post>(); // Collection navigation containing dependents
}

// Dependent (child)
public class Post
{
    public int Id { get; set; }
    public Blog Blog { get; set; } = null!; // Required reference navigation to principal
}

Bazı durumlarda, yabancı anahtarlar ilişki yalnızca nesne odaklı bir şekilde kullanılırken gerekli olmayan veritabanında nasıl temsil edilir bir ayrıntı olduğundan, modelinizde yabancı anahtar özelliği istemeyebilirsiniz. Bununla birlikte, varlıklar örneğin bir kablo üzerinden göndermek üzere seri hale getirilecekse, yabancı anahtar değerleri, varlıklar nesne biçiminde olmadığında ilişki bilgilerini olduğu gibi tutmanın kullanışlı bir yolu olabilir. Bu nedenle, bu amaç için yabancı anahtar özelliklerini .NET türünde tutmak genellikle pragmatiktir. Yabancı anahtar özellikleri özel olabilir, bu da değerinin varlıkla birlikte hareket etmelerine izin verirken yabancı anahtarı açığa çıkarmaktan kaçınmak için genellikle iyi bir risktir.

Önceki iki örnekten sonra, bu örnek bağımlı varlık türünden yabancı anahtar özelliğini kaldırır. Bu nedenle EF, türünde intadlı BlogId bir gölge yabancı anahtar özelliği oluşturur.

Burada dikkat edilmesi gereken önemli noktalardan biri, C# null atanabilir başvuru türlerinin kullanılmasıdır; bu nedenle başvuru gezintisinin null atanabilirliği, yabancı anahtar özelliğinin null atanabilir olup olmadığını ve dolayısıyla ilişkinin isteğe bağlı veya gerekli olup olmadığını belirlemek için kullanılır. Null atanabilir başvuru türleri kullanılmıyorsa, gölge yabancı anahtar özelliği varsayılan olarak null atanabilir olur ve bu da ilişkiyi varsayılan olarak isteğe bağlı hale getirir. Bu durumda, gölge yabancı anahtar özelliğini null atanamaz duruma getirmek ve ilişkiyi gerekli hale getirmek için kullanın IsRequired .

Daha önce olduğu gibi, bu ilişki kural tarafından bulunur. Gezintilerin, yabancı anahtarın veya ilişkinin gerekli/isteğe bağlı doğasının kurala göre keşfedilmediği durumlarda, bu öğeler açıkça yapılandırılabilir. Örneğin:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasMany(e => e.Posts)
        .WithOne(e => e.Blog)
        .HasForeignKey("BlogId")
        .IsRequired();
}

Gölge yabancı anahtarla isteğe bağlı bire çok

// Principal (parent)
public class Blog
{
    public int Id { get; set; }
    public ICollection<Post> Posts { get; } = new List<Post>(); // Collection navigation containing dependents
}

// Dependent (child)
public class Post
{
    public int Id { get; set; }
    public Blog? Blog { get; set; } // Optional reference navigation to principal
}

Önceki örnekte olduğu gibi yabancı anahtar özelliği de bağımlı varlık türünden kaldırılmıştır. Bu nedenle EF, türünde int?adlı BlogId bir gölge yabancı anahtar özelliği oluşturur. Önceki örnekten farklı olarak, C# null atanabilir başvuru türleri kullanıldığından ve bağımlı varlık türündeki gezinti null atanabilir olduğundan bu kez yabancı anahtar özelliği null atanabilir olarak oluşturulur. Bu, ilişkiyi isteğe bağlı hale getirir.

C# null atanabilir başvuru türleri kullanılmadığında, yabancı anahtar özelliği de varsayılan olarak null atanabilir olarak oluşturulur. Bu, otomatik olarak oluşturulan gölge özelliklerine sahip ilişkilerin varsayılan olarak isteğe bağlı olduğu anlamına gelir.

Daha önce olduğu gibi, bu ilişki kural tarafından bulunur. Gezintilerin, yabancı anahtarın veya ilişkinin gerekli/isteğe bağlı doğasının kurala göre keşfedilmediği durumlarda, bu öğeler açıkça yapılandırılabilir. Örneğin:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasMany(e => e.Posts)
        .WithOne(e => e.Blog)
        .HasForeignKey("BlogId")
        .IsRequired(false);
}

Sorumluya gezinti olmadan bire çok

// Principal (parent)
public class Blog
{
    public int Id { get; set; }
    public ICollection<Post> Posts { get; } = new List<Post>(); // Collection navigation containing dependents
}

// Dependent (child)
public class Post
{
    public int Id { get; set; }
    public int BlogId { get; set; } // Required foreign key property
}

Bu örnekte yabancı anahtar özelliği yeniden kullanıma sunulmuştur, ancak bağımlıdaki gezinti kaldırılmıştır.

İpucu

Tek gezinti içeren, biri bağımlıdan sorumluya veya biri sorumludan bağımlıya(lar) ancak her ikisini birden olmayan bir ilişki, tek yönlü ilişki olarak bilinir.

Daha önce olduğu gibi, bu ilişki kural tarafından bulunur. Gezintilerin, yabancı anahtarın veya ilişkinin gerekli/isteğe bağlı doğasının kurala göre keşfedilmediği durumlarda, bu öğeler açıkça yapılandırılabilir. Örneğin:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasMany(e => e.Posts)
        .WithOne()
        .HasForeignKey(e => e.BlogId)
        .IsRequired();
}

çağrısının WithOne bağımsız değişkeni olmadığına dikkat edin. EF'e ile Post Bloggezinti olmadığını söylemenin yolu budur.

Yapılandırma, gezinti olmadan varlıktan başlıyorsa, ilişkinin diğer ucundaki varlığın türü genel HasOne<>() çağrı kullanılarak açıkça belirtilmelidir. Örneğin:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Post>()
        .HasOne<Blog>()
        .WithMany(e => e.Posts)
        .HasForeignKey(e => e.BlogId)
        .IsRequired();
}

Sorumluya ve gölge yabancı anahtara gezinti olmadan bire çok

// Principal (parent)
public class Blog
{
    public int Id { get; set; }
    public ICollection<Post> Posts { get; } = new List<Post>(); // Collection navigation containing dependents
}

// Dependent (child)
public class Post
{
    public int Id { get; set; }
}

Bu örnek, hem yabancı anahtar özelliğini hem de bağımlıdaki gezintiyi kaldırarak önceki örneklerden ikisini birleştirir.

Bu ilişki isteğe bağlı bir ilişki olarak kural tarafından bulunur. Kodda gerekli olması gerektiğini belirtmek için kullanılabilecek bir şey olmadığından, gerekli bir ilişki oluşturmak için kullanımı IsRequired en düşük yapılandırmaya ihtiyaç duyulmaktadır. Örneğin:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasMany(e => e.Posts)
        .WithOne()
        .IsRequired();
}

Gezinti ve yabancı anahtar adını gerektiği gibi uygun bir çağrıyla açıkça yapılandırmak için IsRequired() IsRequired(false) daha eksiksiz bir yapılandırma kullanılabilir. Örneğin:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasMany(e => e.Posts)
        .WithOne()
        .HasForeignKey("BlogId")
        .IsRequired();
}

Bağımlılara gezinti olmadan bire çok

// Principal (parent)
public class Blog
{
    public int Id { get; set; }
}

// Dependent (child)
public class Post
{
    public int Id { get; set; }
    public int BlogId { get; set; } // Required foreign key property
    public Blog Blog { get; set; } = null!; // Required reference navigation to principal
}

Önceki iki örnekte sorumludan bağımlılara gezintiler vardı, ancak bağımlı olandan sorumluya gezinti yoktu. Sonraki birkaç örnek için bağımlı üzerindeki gezinti yeniden tanıtılırken, bunun yerine sorumludaki gezinti kaldırılır.

Daha önce olduğu gibi, bu ilişki kural tarafından bulunur. Gezintilerin, yabancı anahtarın veya ilişkinin gerekli/isteğe bağlı doğasının kurala göre keşfedilmediği durumlarda, bu öğeler açıkça yapılandırılabilir. Örneğin:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Post>()
        .HasOne(e => e.Blog)
        .WithMany()
        .HasForeignKey(e => e.BlogId)
        .IsRequired();
}

WithMany() Bu yönde gezinti olmadığını belirtmek için bağımsız değişken olmadan yeniden çağrıldığını göreceksiniz.

Yapılandırma, gezinti olmadan varlıktan başlıyorsa, ilişkinin diğer ucundaki varlığın türü genel HasMany<>() çağrı kullanılarak açıkça belirtilmelidir. Örneğin:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasMany<Post>()
        .WithOne(e => e.Blog)
        .HasForeignKey(e => e.BlogId)
        .IsRequired();
}

Gezintisi olmayan bire çok

Bazen gezinti olmadan bir ilişki yapılandırmak yararlı olabilir. Böyle bir ilişki yalnızca doğrudan yabancı anahtar değeri değiştirilerek işlenebilir.

// Principal (parent)
public class Blog
{
    public int Id { get; set; }
}

// Dependent (child)
public class Post
{
    public int Id { get; set; }
    public int BlogId { get; set; } // Required foreign key property
}

bu ilişki kural tarafından keşfedilmemiştir, çünkü iki türün ilişkili olduğunu gösteren gezinti yoktur. içinde açıkça OnModelCreatingyapılandırılabilir. Örneğin:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasMany<Post>()
        .WithOne();
}

Bu yapılandırmayla Post.BlogId , özellik kurala göre yabancı anahtar olarak algılanır ve yabancı anahtar özelliği null atanamaz olduğundan ilişki gereklidir. yabancı anahtar özelliği null atanabilir hale getirilerek ilişki "isteğe bağlı" yapılabilir.

Bu ilişkinin daha eksiksiz bir açık yapılandırması:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasMany<Post>()
        .WithOne()
        .HasForeignKey(e => e.BlogId)
        .IsRequired();
}

Alternatif anahtarla bire çok

Şimdiye kadarki tüm örneklerde, bağımlı üzerindeki yabancı anahtar özelliği sorumludaki birincil anahtar özelliğiyle kısıtlandı. Bunun yerine yabancı anahtar farklı bir özelliğe kısıtlanabilir ve bu da asıl varlık türü için alternatif anahtar olur. Örneğin:

// Principal (parent)
public class Blog
{
    public int Id { get; set; }
    public int AlternateId { get; set; } // Alternate key as target of the Post.BlogId foreign key
    public ICollection<Post> Posts { get; } = new List<Post>(); // Collection navigation containing dependents
}

// Dependent (child)
public class Post
{
    public int Id { get; set; }
    public int BlogId { get; set; } // Required foreign key property
    public Blog Blog { get; set; } = null!; // Required reference navigation to principal
}

EF her zaman kurala göre birincil anahtarla bir ilişki oluşturacağı için bu ilişki kurala göre keşfedilmemiştir. çağrısı kullanılarak HasPrincipalKeyaçıkça OnModelCreating yapılandırılabilir. Örneğin:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasMany(e => e.Posts)
        .WithOne(e => e.Blog)
        .HasPrincipalKey(e => e.AlternateId);
}

HasPrincipalKey gezintileri, yabancı anahtar özelliklerini ve gerekli/isteğe bağlı doğayı açıkça yapılandırmak için diğer çağrılarla birleştirilebilir. Örneğin:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasMany(e => e.Posts)
        .WithOne(e => e.Blog)
        .HasPrincipalKey(e => e.AlternateId)
        .HasForeignKey(e => e.BlogId)
        .IsRequired();
}

Bileşik yabancı anahtarla bire çok

Şimdiye kadarki tüm örneklerde, sorumlunun birincil veya alternatif anahtar özelliği tek bir özellik içermektedir. Birincil veya alternatif anahtarlar birden fazla özellikten de oluşturulabilir; bunlar "bileşik anahtarlar" olarak bilinir. bir ilişkinin sorumlusu bileşik anahtara sahip olduğunda, bağımlının yabancı anahtarı da aynı sayıda özelliğe sahip bir bileşik anahtar olmalıdır. Örneğin:

// Principal (parent)
public class Blog
{
    public int Id1 { get; set; } // Composite key part 1
    public int Id2 { get; set; } // Composite key part 2
    public ICollection<Post> Posts { get; } = new List<Post>(); // Collection navigation containing dependents
}

// Dependent (child)
public class Post
{
    public int Id { get; set; }
    public int BlogId1 { get; set; } // Required foreign key property part 1
    public int BlogId2 { get; set; } // Required foreign key property part 2
    public Blog Blog { get; set; } = null!; // Required reference navigation to principal
}

Bu ilişki kural tarafından bulunur. Ancak bileşik anahtarın kendisi açıkça yapılandırılmalıdır:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasKey(e => new { e.Id1, e.Id2 });
}

Önemli

Bileşik yabancı anahtar değeri, özellik değerlerinden herhangi biri null olduğunda kabul edilir null . Bir özelliği null olan ve null olmayan başka bir bileşik yabancı anahtar, aynı değerlere sahip bir birincil veya alternatif anahtar için eşleşme olarak kabul edilmez. Her ikisi de olarak kabul nulledilir.

Hem hem HasPrincipalKey de HasForeignKey birden çok özelliğe sahip anahtarları açıkça belirtmek için kullanılabilir. Örneğin:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>(
        nestedBuilder =>
        {
            nestedBuilder.HasKey(e => new { e.Id1, e.Id2 });

            nestedBuilder.HasMany(e => e.Posts)
                .WithOne(e => e.Blog)
                .HasPrincipalKey(e => new { e.Id1, e.Id2 })
                .HasForeignKey(e => new { e.BlogId1, e.BlogId2 })
                .IsRequired();
        });
}

İpucu

Yukarıdaki kodda ve çağrıları HasKey HasMany iç içe yerleştirilmiş bir oluşturucuda birlikte gruplandırılmıştır. İç içe oluşturucular aynı varlık türü için birden çok kez çağırma Entity<>() gereksinimini ortadan kaldırır, ancak işlevsel olarak birden çok kez çağırmaya Entity<>() eşdeğerdir.

Art arda silme olmadan bire çok gerekli

// Principal (parent)
public class Blog
{
    public int Id { get; set; }
    public ICollection<Post> Posts { get; } = new List<Post>(); // Collection navigation containing dependents
}

// Dependent (child)
public class Post
{
    public int Id { get; set; }
    public int BlogId { get; set; } // Required foreign key property
    public Blog Blog { get; set; } = null!; // Required reference navigation to principal
}

Kural gereği, gerekli ilişkiler art arda silinecek şekilde yapılandırılır; bu, sorumlu silindiğinde, bağımlılar veritabanında sorumlu olmadan var olamayacağından, tüm bağımlılarının da silindiği anlamına gelir. EF'yi artık varolmayabilecek bağımlı satırları otomatik olarak silmek yerine özel durum oluşturacak şekilde yapılandırmak mümkündür:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasMany(e => e.Posts)
        .WithOne(e => e.Blog)
        .OnDelete(DeleteBehavior.Restrict);
}

Kendi kendine başvuran bire çok

Önceki tüm örneklerde, asıl varlık türü bağımlı varlık türünden farklıydı. Böyle olması gerekmez. Örneğin, aşağıdaki türlerde her Employee biri diğer Employeesile ilişkilidir.

public class Employee
{
    public int Id { get; set; }

    public int? ManagerId { get; set; } // Optional foreign key property
    public Employee? Manager { get; set; } // Optional reference navigation to principal
    public ICollection<Employee> Reports { get; } = new List<Employee>(); // Collection navigation containing dependents
}

Bu ilişki kural tarafından bulunur. Gezintilerin, yabancı anahtarın veya ilişkinin gerekli/isteğe bağlı doğasının kurala göre keşfedilmediği durumlarda, bu öğeler açıkça yapılandırılabilir. Örnek:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Employee>()
        .HasOne(e => e.Manager)
        .WithMany(e => e.Reports)
        .HasForeignKey(e => e.ManagerId)
        .IsRequired(false);
}