Entity Framework 查漏補缺 (三)

Code First的數據庫映射

有兩種方式來實現數據庫映射:html

  • 數據屬性:Data Annotation
  • 映射配置: Fluent API

有繼承關係的實體如何映射?git

  • Code First在生成數據庫表時,默認使用TPH方式

就是把父類和子類生成同一張表,額外增長了一列Discriminator字段,區分是父類或子類的數據類型github

好比:數據庫

父類Book對象併發

public class Book
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int BookID { get; set; }
    public string BookName { get; set; }
    public int Pages { get; set; }
}

子類HistoryBooks對象,繼承Bookapp

public class HistoryBooks:Book
{
    public int Chapter { get; set; }
}

數據庫生成一張表ide

 

  • 另外一種方式(Data Annotation實現):TPT

無論父類子類,各自生成一張表,以及在子類中增長二者聯繫的外鍵;ui

定義TPT方式 父類和子類定義 [Table("XXX")]this

如:spa

父類

[Table("Book")]
public class Book
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int BookID { get; set; }
    public string BookName { get; set; }
    public int Pages { get; set; }
}

子類

[Table("HistoryBooks")]
public class HistoryBooks:Book
{public int Chapter { get; set; }
}

映射數據生成的兩張表

Book:

    

HistoryBooks:

映射方式一:Data Annotation

給實體對象的屬性加上註解特性,實現與數據庫之間創建映射關係並進行控制

 如:

Booid映射到表中字段爲自增的主鍵

DataAnnotations 包含的經常使用特性:

KeyAttribute:對應數據庫中表的主鍵的設置

RequiredAttribute:對應數據庫中字段的數據不可null

MaxLengthAttribute:對應數據庫中字符串類型字段的最大長度

ConcurrencyCheckAttribute:指定用於開放式併發檢查的列的數據類型

TimestampAttribute:將列的數據類型指定爲行版本

DatabaseGeneratedAttribute:標記指定實體屬性是由數據庫生成的,並指定生成策略(None數據庫不生成值,Identity當插入行時,數據庫生成值,Computed當插入或更新行時,數據庫生成值)

TableAttribute:指定實體類對應的數據表名

ColumnAttribute:指定實體屬性在數據庫中的列名

ForeignKeyAttribute :指定導航屬性的外鍵字段

NotMappeAttribute:不映射對應字段

映射方式二:Fluent API

Fluent API的配置方式能夠將實體類與映射配置進行解耦合

有兩種方式來實現Fluent API的映射配置

  • 第一種:重寫Dbcontext的中OnModelCreating方法

以下面的Book類,再也不有Data Annotation特性

public class Book
{
    public int BookID { get; set; }
    public string BookName { get; set; }
    public int Pages { get; set; }
}

重寫Dbcontext中的OnModelCreating方法實現Book類映射的配置:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<Book>().HasKey(t => t.BookID);

    base.OnModelCreating(modelBuilder);
}

現實項目中,實體對象多是很是多的,在OnModelCreating方法中逐一進行映射配置,可想而知會形成Dbcontext的代碼龐大。

  • 第二種:新建BookMap類,並繼承EntityTypeConfiguration<EntityType>

一、在新建的BookMap類實現映射配置

public class BookMap : EntityTypeConfiguration<Book>
{
    public BookMap()
    {
        this.ToTable("Book", "dbo");
        this.HasKey(p => p.BookID);
        //this.HasKey(p => new { p.BookID, p.BookPreID });//關聯主鍵  
        this.Property(p => p.BookID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);//自動生成
        this.Property(p => p.BookName).IsRequired().HasMaxLength(20).HasColumnName("BookName").IsUnicode(false);//非空,最大長度20,自定義列名,列類型爲varchar而非nvarchar
        this.Ignore(p => p.BookDescription);//忽略改屬性的映射
    }
}

二、依舊重寫Dbcontext中的OnModelCreating方法,將BookMap 類的實例添加到modelBuilder的Configurations。

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Configurations.Add(new BookMap());
}

這樣能大大減小OnModelCreating的代碼量,依然存在一個問題,就是實體對象一多,仍是要逐條將Map類的實例添加到modelBuilder的Configurations

三、利用反射將程序集中全部的EntityTypeConfiguration添加到modelBuilder.Configurations中,能夠說徹底解耦了

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    var typesToRegister = Assembly.GetExecutingAssembly().GetTypes()
                        .Where(type => !String.IsNullOrEmpty(type.Namespace))
                        .Where(type => type.BaseType != null && type.BaseType.IsGenericType && type.BaseType.GetGenericTypeDefinition() == typeof(EntityTypeConfiguration<>));
    foreach (var type in typesToRegister)
    {
        dynamic configurationInstance = Activator.CreateInstance(type);
        modelBuilder.Configurations.Add(configurationInstance);
    }
}

注:此段代碼源自網友文章,摘自nopCommerce項目的代碼  鏈接

相關文章
相關標籤/搜索