Fluent API - Özellikleri ve Türleri Yapılandırma ve Eşleme

Entity Framework Code first ile çalışırken varsayılan davranış, EF'de pişirilen bir dizi kuralı kullanarak POCO sınıflarınızı tablolara eşlemektir. Ancak bazen bu kuralları uygulayamaz veya izlemek istemezsiniz ve varlıkları kuralların dikte ettikleri dışında bir şeyle eşlemeniz gerekir.

EF'yi kurallar dışında bir şey kullanacak şekilde yapılandırmanın iki ana yolu vardır: ek açıklamalar veya EFs akıcı API'leri. Ek açıklamalar yalnızca akıcı API işlevselliğinin bir alt kümesini kapsar, bu nedenle ek açıklamalar kullanılarak ulaşılamayan eşleme senaryoları vardır. Bu makale, özellikleri yapılandırmak için akıcı API'nin nasıl kullanılacağını göstermek için tasarlanmıştır.

Kod ilk akıcı API'sine genellikle türetilmiş DbContext'inizde OnModelCreating yöntemi geçersiz kılınarak erişilir. Aşağıdaki örnekler, akıcı API ile çeşitli görevlerin nasıl gerçekleştirileceğini göstermek ve kodu kopyalayıp modelinize uyacak şekilde özelleştirmenize olanak sağlamak için tasarlanmıştır. Bu örnekte olduğu gibi kullanabilecekleri modeli görmek isterseniz, bu makalenin sonunda sağlanır.

Model Genelinde Ayarlar

Varsayılan Şema (EF6 devamı)

EF6'dan başlayarak DbModelBuilder'da HasDefaultSchema yöntemini kullanarak tüm tablolar, saklı yordamlar vb. için kullanılacak veritabanı şemasını belirtebilirsiniz. Bu varsayılan ayar, farklı bir şemayı açıkça yapılandırdığınız tüm nesneler için geçersiz kılınacaktır.

modelBuilder.HasDefaultSchema("sales");

Özel Kurallar (EF6 ve üzeri)

EF6'dan başlayarak, Önce Kod'a dahil olanları desteklemek için kendi kurallarınızı oluşturabilirsiniz. Daha fazla ayrıntı için bkz . Özel Kod İlk Kuralları.

Özellik Eşlemesi

Property yöntemi, bir varlığa veya karmaşık türe ait her özelliğin özniteliklerini yapılandırmak için kullanılır. Property yöntemi, belirli bir özelliğin yapılandırma nesnesini almak için kullanılır. Yapılandırma nesnesinde seçenekler yapılandırılan türe özgü; IsUnicode yalnızca dize özelliklerinde kullanılabilir.

Birincil Anahtar Yapılandırma

Birincil anahtarlar için Entity Framework kuralı şöyledir:

  1. Sınıfınız adı "ID" veya "Id" olan bir özellik tanımlar
  2. veya bir sınıf adı ve ardından "ID" veya "Id"

Bir özelliği açıkça birincil anahtar olarak ayarlamak için HasKey yöntemini kullanabilirsiniz. Aşağıdaki örnekte, OfficeAssignment türünde InstructorID birincil anahtarını yapılandırmak için HasKey yöntemi kullanılır.

modelBuilder.Entity<OfficeAssignment>().HasKey(t => t.InstructorID);

Bileşik Birincil Anahtar Yapılandırma

Aşağıdaki örnekte DepartmentID ve Name özellikleri, Departman türünün bileşik birincil anahtarı olacak şekilde yapılandırılır.

modelBuilder.Entity<Department>().HasKey(t => new { t.DepartmentID, t.Name });

Sayısal Birincil Anahtarlar için Kimlik'i kapatma

Aşağıdaki örnek, değerin veritabanı tarafından oluşturulacağını belirtmek için DepartmentID özelliğini System.ComponentModel.DataAnnotations.DatabaseGeneratedOption.None olarak ayarlar.

modelBuilder.Entity<Department>().Property(t => t.DepartmentID)
    .HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);

Bir Özellikte En Fazla Uzunluğu Belirtme

Aşağıdaki örnekte Name özelliği 50 karakterden uzun olmamalıdır. Değeri 50 karakterden uzun yaparsanız DbEntityValidationException özel durumu alırsınız. Code First bu modelden bir veritabanı oluşturursa, Ad sütununun uzunluk üst sınırını da 50 karakter olarak ayarlar.

modelBuilder.Entity<Department>().Property(t => t.Name).HasMaxLength(50);

Özelliği Gerekli Olacak Şekilde Yapılandırma

Aşağıdaki örnekte Name özelliği gereklidir. Ad belirtmezseniz DbEntityValidationException özel durumu alırsınız. Code First bu modelden bir veritabanı oluşturursa, bu özelliği depolamak için kullanılan sütun genellikle null değer atanamaz olur.

Dekont

Bazı durumlarda, özellik gerekli olsa bile veritabanındaki sütunun null atanamaz olması mümkün olmayabilir. Örneğin, birden çok tür için TPH devralma stratejisi verileri kullanılırken tek bir tabloda depolanır. Türetilmiş bir tür gerekli bir özellik içeriyorsa, hiyerarşideki tüm türler bu özelliğe sahip olmadığından sütun null atanamaz hale getirilemez.

modelBuilder.Entity<Department>().Property(t => t.Name).IsRequired();

Bir veya daha fazla özellikte Dizin yapılandırma

Dekont

EF6.1 Yalnızca Devam Eden - Index özniteliği Entity Framework 6.1'de tanıtıldı. Önceki bir sürümü kullanıyorsanız bu bölümdeki bilgiler geçerli değildir.

Dizin oluşturma, Fluent API tarafından yerel olarak desteklenmez, ancak Fluent API aracılığıyla IndexAttribute desteğinden yararlanabilirsiniz. Dizin öznitelikleri, daha sonra işlem hattında veritabanında dizine dönüştürülen modele model ek açıklaması eklenerek işlenir. Fluent API'sini kullanarak aynı ek açıklamaları el ile ekleyebilirsiniz.

Bunu yapmanın en kolay yolu, yeni dizinin tüm ayarlarını içeren bir IndexAttribute örneği oluşturmaktır. Ardından, IndexAttribute ayarlarını EF modelinde depolanabilecek bir model ek açıklamasına dönüştürecek EF'ye özgü bir tür olan IndexAnnotation örneğini oluşturabilirsiniz. Bunlar daha sonra Fluent API'sinde HasColumnAnnotation yöntemine geçirilebilir ve ek açıklama için Dizin adı belirtilebilir.

modelBuilder
    .Entity<Department>()
    .Property(t => t.Name)
    .HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute()));

IndexAttribute'ta bulunan ayarların tam listesi için, Kod İlk Veri Ek Açıklamaları'nın Dizin bölümüne bakın. Buna dizin adını özelleştirme, benzersiz dizinler oluşturma ve çok sütunlu dizinler oluşturma dahildir.

IndexAnnotation oluşturucusunun indexAttribute dizisini geçirerek tek bir özellik üzerinde birden çok dizin ek açıklaması belirtebilirsiniz.

modelBuilder
    .Entity<Department>()
    .Property(t => t.Name)
    .HasColumnAnnotation(
        "Index",  
        new IndexAnnotation(new[]
            {
                new IndexAttribute("Index1"),
                new IndexAttribute("Index2") { IsUnique = true }
            })));

CLR Özelliğini Veritabanındaki Bir Sütuna Eşlemek için Değil Belirtme

Aşağıdaki örnekte, CLR türündeki bir özelliğin veritabanındaki bir sütuna eşlenmediğini belirtme işlemi gösterilmektedir.

modelBuilder.Entity<Department>().Ignore(t => t.Budget);

CLR Özelliğini Veritabanındaki Belirli Bir Sütuna Eşleme

Aşağıdaki örnek Name CLR özelliğini DepartmentName veritabanı sütunuyla eşler.

modelBuilder.Entity<Department>()
    .Property(t => t.Name)
    .HasColumnName("DepartmentName");

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

CLR türünde 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"));

Dize Özelliğinin Unicode İçeriğiNi Destekleyip Desteklemediğini Yapılandırma

Varsayılan olarak dizeler Unicode 'dır (SQL Server'da nvarchar). Bir dizenin varchar türünde olması gerektiğini belirtmek için IsUnicode yöntemini kullanabilirsiniz.

modelBuilder.Entity<Department>()
    .Property(t => t.Name)
    .IsUnicode(false);

Veritabanı Sütununun Veri Türünü Yapılandırma

HasColumnType yöntemi, aynı temel türün farklı gösterimlerine eşlemeyi etkinleştirir. Bu yöntemin kullanılması, çalışma zamanında veri dönüştürme işlemi gerçekleştirmenizi sağlamaz. IsUnicode'un, veritabanı belirsiz olduğundan sütunları varchar olarak ayarlamanın tercih edilen yolu olduğunu unutmayın.

modelBuilder.Entity<Department>()   
    .Property(p => p.Name)   
    .HasColumnType("varchar");

Karmaşık Türde Özellikleri Yapılandırma

Karmaşık bir türde skaler özellikleri yapılandırmanın iki yolu vardır.

ComplexTypeConfiguration üzerinde Özelliği çağırabilirsiniz.

modelBuilder.ComplexType<Details>()
    .Property(t => t.Location)
    .HasMaxLength(20);

Ayrıca, karmaşık türdeki bir özelliğe erişmek için nokta gösterimini de kullanabilirsiniz.

modelBuilder.Entity<OnsiteCourse>()
    .Property(t => t.Details.Location)
    .HasMaxLength(20);

İyimser Eşzamanlılık Belirteci Olarak Kullanılacak Bir Özelliği Yapılandırma

Varlıktaki bir özelliğin eşzamanlılık belirtecini temsil ettiğini belirtmek için ConcurrencyCheck özniteliğini veya IsConcurrencyToken yöntemini kullanabilirsiniz.

modelBuilder.Entity<OfficeAssignment>()
    .Property(t => t.Timestamp)
    .IsConcurrencyToken();

Özelliği veritabanında satır sürümü olacak şekilde yapılandırmak için IsRowVersion yöntemini de kullanabilirsiniz. Özelliğin satır sürümü olarak ayarlanması, otomatik olarak iyimser bir eşzamanlılık belirteci olacak şekilde yapılandırılır.

modelBuilder.Entity<OfficeAssignment>()
    .Property(t => t.Timestamp)
    .IsRowVersion();

Tür Eşlemesi

Sınıfın Karmaşık Bir Tür Olduğunu Belirtme

Kural gereği, birincil anahtar belirtilmemiş bir tür karmaşık tür olarak kabul edilir. Code First'ın karmaşık bir tür algılamadığı bazı senaryolar vardır (örneğin, ID adlı bir özelliğiniz varsa, ancak bunun birincil anahtar olmasını istemiyorsanız). Böyle durumlarda, bir türün karmaşık bir tür olduğunu açıkça belirtmek için akıcı API'yi kullanırsınız.

modelBuilder.ComplexType<Details>();

CLR Varlık Türünü Veritabanındaki Bir Tabloya Eşlemek için Değil Belirtme

Aşağıdaki örnekte, clr türünün veritabanındaki bir tabloyla eşlenmesinin nasıl dışlandığı gösterilmektedir.

modelBuilder.Ignore<OnlineCourse>();

Varlık Türünü Veritabanındaki Belirli Bir Tabloyla Eşleme

Department'ın tüm özellikleri, t_ Department adlı bir tablodaki sütunlara eşlenir.

modelBuilder.Entity<Department>()  
    .ToTable("t_Department");

Şema adını aşağıdaki gibi de belirtebilirsiniz:

modelBuilder.Entity<Department>()  
    .ToTable("t_Department", "school");

Hiyerarşi Başına Tablo (TPH) Devralmayı Eşleme

TPH eşleme senaryosunda, devralma hiyerarşisindeki tüm türler tek bir tabloya eşlenir. Ayrıştırıcı sütunu, her satırın türünü tanımlamak için kullanılır. Modelinizi Code First ile oluştururken, devralma hiyerarşisine katılan türler için varsayılan strateji TPH'dir. Varsayılan olarak, ayrımcı sütunu tabloya "Ayırıcı" adıyla eklenir ve ayrımcı değerler için hiyerarşideki her türün CLR türü adı kullanılır. Akıcı API'yi kullanarak varsayılan davranışı değiştirebilirsiniz.

modelBuilder.Entity<Course>()  
    .Map<Course>(m => m.Requires("Type").HasValue("Course"))  
    .Map<OnsiteCourse>(m => m.Requires("Type").HasValue("OnsiteCourse"));

Tür Başına Tablo (TPT) Devralmayı Eşleme

TPT eşleme senaryosunda tüm türler tek tek tablolara eşlenir. Yalnızca bir temel türe veya türetilmiş türe ait özellikler, bu türle eşlenen bir tabloda depolanır. Türetilmiş türlerle eşlenen tablolar, türetilmiş tabloyu temel tabloyla birleştiren bir yabancı anahtar da depolar.

modelBuilder.Entity<Course>().ToTable("Course");  
modelBuilder.Entity<OnsiteCourse>().ToTable("OnsiteCourse");

Somut Sınıf Başına Tablo (TPC) Devralmayı Eşleme

TPC eşleme senaryosunda, hiyerarşideki tüm soyut olmayan türler tek tek tablolara eşlenir. Türetilmiş sınıflarla eşlenen tabloların veritabanındaki temel sınıfla eşlenen tabloyla hiçbir ilişkisi yoktur. Devralınan özellikler de dahil olmak üzere bir sınıfın tüm özellikleri ilgili tablonun sütunlarına eşlenir.

Türetilmiş her türü yapılandırmak için MapInheritedProperties yöntemini çağırın. MapInheritedProperties, temel sınıftan devralınan tüm özellikleri türetilmiş sınıfın tablosundaki yeni sütunlara yeniden eşler.

Dekont

TPC devralma hiyerarşisine katılan tablolar birincil anahtarı paylaşmadığı için, veritabanı tarafından aynı kimlik tohumuyla oluşturulan değerlere sahipseniz, alt sınıflara eşlenen tablolar eklerken yinelenen varlık anahtarları olacağını unutmayın. Bu sorunu çözmek için her tablo için farklı bir ilk tohum değeri belirtebilir veya birincil anahtar özelliğinde kimliği kapatabilirsiniz. Kimlik, Code First ile çalışırken tamsayı anahtarı özellikleri için varsayılan değerdir.

modelBuilder.Entity<Course>()
    .Property(c => c.CourseID)
    .HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);

modelBuilder.Entity<OnsiteCourse>().Map(m =>
{
    m.MapInheritedProperties();
    m.ToTable("OnsiteCourse");
});

modelBuilder.Entity<OnlineCourse>().Map(m =>
{
    m.MapInheritedProperties();
    m.ToTable("OnlineCourse");
});

Varlık Türünün Özelliklerini Veritabanındaki Birden Çok Tabloya Eşleme (Varlık Bölme)

Varlık bölme, varlık türünün özelliklerinin birden çok tabloya yayılmasını sağlar. Aşağıdaki örnekte Department varlığı iki tabloya ayrılmıştır: Department ve DepartmentDetails. Varlık bölme, özelliklerin bir alt kümesini belirli bir tabloyla eşlemek için Map yöntemine birden çok çağrı kullanır.

modelBuilder.Entity<Department>()
    .Map(m =>
    {
        m.Properties(t => new { t.DepartmentID, t.Name });
        m.ToTable("Department");
    })
    .Map(m =>
    {
        m.Properties(t => new { t.DepartmentID, t.Administrator, t.StartDate, t.Budget });
        m.ToTable("DepartmentDetails");
    });

Birden Çok Varlık Türünü Veritabanındaki Bir Tabloya Eşleme (Tablo Bölme)

Aşağıdaki örnek, birincil anahtarı paylaşan iki varlık türünü bir tabloyla eşler.

modelBuilder.Entity<OfficeAssignment>()
    .HasKey(t => t.InstructorID);

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

modelBuilder.Entity<Instructor>().ToTable("Instructor");

modelBuilder.Entity<OfficeAssignment>().ToTable("Instructor");

Varlık Türünü Saklı Yordamları Ekleme/Güncelleştirme/Silme ile Eşleme (EF6 ve üzeri)

EF6'dan başlayarak, ekleme güncelleştirmesi ve silme için saklı yordamları kullanmak üzere bir varlığı eşleyebilirsiniz. Daha fazla ayrıntı için bkz. Kod İlk Ekleme/Güncelleştirme/Saklı Yordamları Silme.

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