Fluent API - İlişkiler

Dekont

Bu sayfa, akıcı API'yi kullanarak Code First modelinizde ilişkileri ayarlama hakkında bilgi sağlar. EF'deki ilişkiler ve ilişkileri kullanarak verilere erişme ve verileri işleme hakkında genel bilgi için bkz . İlişkiler ve Gezinti Özellikleri.

Code First ile çalışırken, etki alanı CLR sınıflarınızı tanımlayarak modelinizi tanımlarsınız. Varsayılan olarak, Entity Framework sınıflarınızı veritabanı şemasına eşlemek için Code First kurallarını kullanır. Code First adlandırma kurallarını kullanırsanız, çoğu durumda sınıflarda tanımladığınız yabancı anahtarlara ve gezinti özelliklerine göre tablolarınız arasındaki ilişkileri ayarlamak için Önce Kod'a güvenebilirsiniz. Sınıflarınızı tanımlarken kuralları izlemezseniz veya kuralların çalışma şeklini değiştirmek istiyorsanız, sınıflarınızı Code First'in tablolarınız arasındaki ilişkileri eşleyebilmesi için sınıflarınızı yapılandırmak için akıcı API'yi veya veri ek açıklamalarını kullanabilirsiniz.

Giriş

Akıcı API ile bir ilişki yapılandırırken, EntityTypeConfiguration örneğiyle başlarsınız ve bu varlığın katıldığı ilişki türünü belirtmek için HasRequired, HasOptional veya HasMany yöntemini kullanırsınız. HasRequired ve HasOptional yöntemleri, başvuru gezinti özelliğini temsil eden bir lambda ifadesi alır. HasMany yöntemi, koleksiyon gezinti özelliğini temsil eden bir lambda ifadesi alır. Ardından, WithRequired, WithOptional ve WithMany yöntemlerini kullanarak ters gezinti özelliğini yapılandırabilirsiniz. Bu yöntemlerin bağımsız değişken almayan aşırı yüklemeleri vardır ve tek yönlü gezintilerle kardinaliteyi belirtmek için kullanılabilir.

Ardından HasForeignKey yöntemini kullanarak yabancı anahtar özelliklerini yapılandırabilirsiniz. Bu yöntem, yabancı anahtar olarak kullanılacak özelliği temsil eden bir lambda ifadesi alır.

Gerekli-İsteğe Bağlı İlişkiyi Yapılandırma (Bire-Sıfıra veya Bir)

Aşağıdaki örnekte bire sıfıra veya bir ilişkisi yapılandırılır. OfficeAssignment birincil anahtar olan InstructorID özelliğine ve yabancı anahtara sahiptir, çünkü özelliğin adı HasKey yönteminin birincil anahtarı yapılandırmak için kullanıldığı kuralı izlemez.

// Configure the primary key for the OfficeAssignment
modelBuilder.Entity<OfficeAssignment>()
    .HasKey(t => t.InstructorID);

// Map one-to-zero or one relationship
modelBuilder.Entity<OfficeAssignment>()
    .HasRequired(t => t.Instructor)
    .WithOptional(t => t.OfficeAssignment);

her iki ucun da gerekli olduğu bir ilişkiyi yapılandırma (bire bir)

Çoğu durumda Entity Framework, hangi türün bağımlı ve hangi ilişkinin sorumlusu olduğunu çıkarsayabilir. Ancak, ilişkinin her iki ucu gerektiğinde veya her iki taraf da isteğe bağlı olduğunda Entity Framework bağımlı ve sorumluyu tanımlayamaz. İlişkinin her iki ucu gerektiğinde, HasRequired yönteminden sonra WithRequiredPrincipal veya WithRequiredDependent kullanın. İlişkinin her iki ucu da isteğe bağlı olduğunda, HasOptional yönteminden sonra WithOptionalPrincipal veya WithOptionalDependent kullanın.

// Configure the primary key for the OfficeAssignment
modelBuilder.Entity<OfficeAssignment>()
    .HasKey(t => t.InstructorID);

modelBuilder.Entity<Instructor>()
    .HasRequired(t => t.OfficeAssignment)
    .WithRequiredPrincipal(t => t.Instructor);

Çoka Çok İlişkisini Yapılandırma

Aşağıdaki kod, Kurs ve Eğitmen türleri arasında çoka çok ilişki yapılandırılır. Aşağıdaki örnekte, birleştirme tablosu oluşturmak için varsayılan Code First kuralları kullanılır. Sonuç olarak CourseInstructor tablosu Course_CourseID ve Instructor_InstructorID sütunlarla oluşturulur.

modelBuilder.Entity<Course>()
    .HasMany(t => t.Instructors)
    .WithMany(t => t.Courses)

Tabloya katılma adını ve tablodaki sütunların adlarını belirtmek istiyorsanız, Map yöntemini kullanarak ek yapılandırma yapmanız gerekir. Aşağıdaki kod, CourseID ve InstructorID sütunlarını içeren CourseInstructor tablosunu oluşturur.

modelBuilder.Entity<Course>()
    .HasMany(t => t.Instructors)
    .WithMany(t => t.Courses)
    .Map(m =>
    {
        m.ToTable("CourseInstructor");
        m.MapLeftKey("CourseID");
        m.MapRightKey("InstructorID");
    });

Bir Gezinti Özelliğiyle İlişki Yapılandırma

Tek yönlü (tek yönlü olarak da adlandırılır) ilişki, gezinti özelliğinin her ikisinde de değil yalnızca bir ilişkide tanımlandığı durumdur. Kural gereği Code First her zaman tek yönlü ilişkiyi bire çok olarak yorumlar. Örneğin, Eğitmen ile OfficeAssignment arasında yalnızca Eğitmen türünde gezinti özelliğine sahip olduğunuz bire bir ilişki istiyorsanız, bu ilişkiyi yapılandırmak için akıcı API'yi kullanmanız gerekir.

// Configure the primary Key for the OfficeAssignment
modelBuilder.Entity<OfficeAssignment>()
    .HasKey(t => t.InstructorID);

modelBuilder.Entity<Instructor>()
    .HasRequired(t => t.OfficeAssignment)
    .WithRequiredPrincipal();

Art Arda Silmeyi Etkinleştirme

WillCascadeOnDelete yöntemini kullanarak bir ilişkide art arda silmeyi yapılandırabilirsiniz. Bağımlı varlık üzerindeki bir yabancı anahtar null atanamazsa, Code First ilişkide art arda silmeyi ayarlar. Bağımlı varlık üzerindeki bir yabancı anahtar null atanabilirse, Code First ilişkide art arda silmeyi ayarlamaz ve sorumlu silindiğinde yabancı anahtar null olarak ayarlanır.

Şu art arda silme kurallarını kaldırmak için şunları kullanabilirsiniz:

modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>()
modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>()

Aşağıdaki kod, ilişkiyi gerekli olacak şekilde yapılandırıp art arda silmeyi devre dışı bırakır.

modelBuilder.Entity<Course>()
    .HasRequired(t => t.Department)
    .WithMany(t => t.Courses)
    .HasForeignKey(d => d.DepartmentID)
    .WillCascadeOnDelete(false);

Bileşik Yabancı Anahtar Yapılandırma

Bölüm türündeki birincil anahtar DepartmentID ve Name özelliklerinden oluşuyorsa, Bölüm için birincil anahtarı ve Kurs türlerinde yabancı anahtarı aşağıdaki gibi yapılandırabilirsiniz:

// Composite primary key
modelBuilder.Entity<Department>()
.HasKey(d => new { d.DepartmentID, d.Name });

// Composite foreign key
modelBuilder.Entity<Course>()  
    .HasRequired(c => c.Department)  
    .WithMany(d => d.Courses)
    .HasForeignKey(d => new { d.DepartmentID, d.DepartmentName });

Modelde Tanımlanmayan Yabancı Anahtarı Yeniden Adlandırma

CLR türünde bir yabancı anahtar tanımlamamayı seçerseniz, ancak veritabanında hangi adın olması gerektiğini belirtmek istiyorsanız, aşağıdakileri yapın:

modelBuilder.Entity<Course>()
    .HasRequired(c => c.Department)
    .WithMany(t => t.Courses)
    .Map(m => m.MapKey("ChangedDepartmentID"));

Kod İlk Kuralına Uymayan Bir Yabancı Anahtar Adı Yapılandırma

Course sınıfındaki yabancı anahtar özelliği DepartmentID yerine SomeDepartmentID olarak adlandırıldıysa SomeDepartmentID değerinin yabancı anahtar olmasını istediğinizi belirtmek için aşağıdakileri yapmanız gerekir:

modelBuilder.Entity<Course>()
         .HasRequired(c => c.Department)
         .WithMany(d => d.Courses)
         .HasForeignKey(c => c.SomeDepartmentID);

Örneklerde Kullanılan Model

Bu sayfadaki örnekler için aşağıdaki İlk Kod modeli kullanılır.

using System.Data.Entity;
using System.Data.Entity.ModelConfiguration.Conventions;
// add a reference to System.ComponentModel.DataAnnotations DLL
using System.ComponentModel.DataAnnotations;
using System.Collections.Generic;
using System;

public class SchoolEntities : DbContext
{
    public DbSet<Course> Courses { get; set; }
    public DbSet<Department> Departments { get; set; }
    public DbSet<Instructor> Instructors { get; set; }
    public DbSet<OfficeAssignment> OfficeAssignments { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        // Configure Code First to ignore PluralizingTableName convention
        // If you keep this convention then the generated tables will have pluralized names.
        modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
    }
}

public class Department
{
    public Department()
    {
        this.Courses = new HashSet<Course>();
    }
    // Primary key
    public int DepartmentID { get; set; }
    public string Name { get; set; }
    public decimal Budget { get; set; }
    public System.DateTime StartDate { get; set; }
    public int? Administrator { get; set; }

    // Navigation property
    public virtual ICollection<Course> Courses { get; private set; }
}

public class Course
{
    public Course()
    {
        this.Instructors = new HashSet<Instructor>();
    }
    // Primary key
    public int CourseID { get; set; }

    public string Title { get; set; }
    public int Credits { get; set; }

    // Foreign key
    public int DepartmentID { get; set; }

    // Navigation properties
    public virtual Department Department { get; set; }
    public virtual ICollection<Instructor> Instructors { get; private set; }
}

public partial class OnlineCourse : Course
{
    public string URL { get; set; }
}

public partial class OnsiteCourse : Course
{
    public OnsiteCourse()
    {
        Details = new Details();
    }

    public Details Details { get; set; }
}

public class Details
{
    public System.DateTime Time { get; set; }
    public string Location { get; set; }
    public string Days { get; set; }
}

public class Instructor
{
    public Instructor()
    {
        this.Courses = new List<Course>();
    }

    // Primary key
    public int InstructorID { get; set; }
    public string LastName { get; set; }
    public string FirstName { get; set; }
    public System.DateTime HireDate { get; set; }

    // Navigation properties
    public virtual ICollection<Course> Courses { get; private set; }
}

public class OfficeAssignment
{
    // Specifying InstructorID as a primary
    [Key()]
    public Int32 InstructorID { get; set; }

    public string Location { get; set; }

    // When Entity Framework sees Timestamp attribute
    // it configures ConcurrencyCheck and DatabaseGeneratedPattern=Computed.
    [Timestamp]
    public Byte[] Timestamp { get; set; }

    // Navigation property
    public virtual Instructor Instructor { get; set; }
}