Entity Framework 6新特性:全局性地自定義Code First約定


2012年12月11日,Entity Framework已經發布了Entity Framework 6 Alpha2,因項目需要,目前已使用了其中的兩個特性,今天就來介紹一下第一個特性:全局性地自定義Code First約定(Custom Code First Conventions)。

應用場景

場景一:EF Code First默認使用類名作為表名,如果我們需要給表名加個前綴,例如將類名Category映射到表Shop_Category、將Product映射到Shop_Product,在EF 6之前,只能一個一個地使用Data Annotation( [Table("Shop_Category")] )或者Fluent API( ToTable("Shop_Category") )一個一個地指定表名。在實體類數量比較多的情況下,工作量就比較大了。

場景二:EF Code First默認將String類型的屬性映射為nvarchar(max),但是你可能想要將它映射為nvarchar(255),那么也可以全局性地自定義,而不需要在所有String類型的屬性上面使用[MaxLength(255)]進行配置。

當然使用場景不只這兩個,如改寫主外鍵的映射規則等等。簡而言之,Custom Code First Conventions使你能夠改寫Entity Framework模型與數據庫之間默認的映射規則。

自定義Code First約定的方式

Code First的默認映射規則可以通過三種方式進行自定義,分別是:Lightweight Conventions(輕量級約定)、Configuration Conventions(配置型約定)、Model-based Conventions(基於模型的配置)。實現上的復雜度由Lightweight Conventions開始依次遞增,當然,實現的自由度也依次增大。

 1 public class ProductContext : DbContext
 2 {
 3     static ProductContext()
 4     {
 5         Database.SetInitializer(
 6             new DropCreateDatabaseIfModelChanges<ProductContext>());
 7     }
 8                                                         
 9     public DbSet<Product> Products { get; set; }
10 }
11                                                         
12 public class Product
13 {
14     public int ProductId { get; set; }
15     public string Name { get; set; }
16     public string? Description {get; set;}
17 }

在這個模型中,默認情況下,EF會生成以下的數據表結構:

表名:Product
字段名稱 類型 是否可空
ProductId int 主鍵
Name
nvarchar(max)
Description
nvarchar(max)

我們以添加表前綴為例,來說明自定義Code First約定的前兩種方式。

Lightweight Conventions

重寫ProductContext的OnModelCreating(DbModelBuilder modelBuilder)方法:

 

1 public class ProductContext : DbContext
2 {
3     protected override void OnModelCreating(DbModelBuilder modelBuilder)
4     {
5        modelBuilder.Types().Configure(entity => entity.ToTable("Shop_" + entity.ClrType.Name));
6     }
7 }

Lightweight Conventions是最簡單的實現方式,大部分的全局配置需求都能夠以這種方式來實現。

Configuration Conventions

實現IConfigurationConvention<Type, EntityTypeConfiguration>接口,然后重寫ProductContext的OnModelCreating(DbModelBuilder modelBuilder)方法。

 

 1 public class DefaultTableConvention
 2 : IConfigurationConvention<Type, EntityTypeConfiguration>
 3 {
 4     public void Apply(
 5         Type type,
 6         Func<EntityTypeConfiguration> configuration)
 7     {
 8         TableAttribute[] tableAttributes = (TableAttribute[])type.GetCustomAttributes(typeof(TableAttribute), false);
 9                                    
10         if (tableAttributes.Length == 0)
11         {                
12             configuration().ToTable("Shop_" + type.Name);
13         }
14     }
15 }
16                                 
17 public class ProductContext : DbContext
18 {
19     protected override void OnModelCreating(DbModelBuilder modelBuilder)
20     {
21        modelBuilder.Conventions.Add<DefaultTableConvention>();
22     }
23 }

 

 

從上面的代碼可以看到,Configuration Conventions的方式需要自行判斷實體是否使用TableAttribute指定了表名,如果是,則不使用全局的配置。而Lightweight Conventions則默認優先使用TableAttribute指定的表名。可以看出,Configuration Conventions實現起來相對繁瑣了一點,但是自由度也更高。

IConfigurationConvention接口有兩個類型參數:TMemberInfo和TConfiguration。它們用來過濾你想自定義約定的模型元素。

第一個類型參數,TMemberInfo,可以是一下兩個值:

  • Type(System)

  • PropertyInfo(System.Reflection)

第二個類型參數,TConfiguration,可以是一下任意一種。

  • ModelConfiguration (System.Data.Entity.ModelConfiguration.Configuration)

  • EntityTypeConfiguration (System.Data.Entity.ModelConfiguration.Configuration.Types)

  • PropertyConfiguration (System.Data.Entity.ModelConfiguration.Configuration.Properties)

  • NavigationPropertyConfiguration (System.Data.Entity.ModelConfiguration.Configuration.Properties.Navigation)

  • PrimitivePropertyConfiguration (System.Data.Entity.ModelConfiguration.Configuration.Properties.Primitive)

    • DateTimePropertyConfiguration (System.Data.Entity.ModelConfiguration.Configuration.Properties.Primitive)

    • DecimalPropertyConfiguration (System.Data.Entity.ModelConfiguration.Configuration.Properties.Primitive)

    • LengthPropertyConfiguration (System.Data.Entity.ModelConfiguration.Configuration.Properties.Primitive)

      • BinaryPropertyConfiguration (System.Data.Entity.ModelConfiguration.Configuration.Properties.Primitive)

      • StringPropertyConfiguration (System.Data.Entity.ModelConfiguration.Configuration.Properties.Primitive)

注意,Type和PropertyConfiguration(以及它的子類)不能混用,否則Configuration Conventions將不會生效。

增加自定義的Data Annotation

利用Custom Code First Conventions,我們還可以擴展自己的Data Annotation。例如,增加一個EmailAttribute特性,然后在Lightweight Conventions或者Configuration Conventions中,判斷屬性是否應用了EmailAttribute特性;如果是,則將列名映射為“Email”,列類型映射為“nvarchar(255)”, 達到了[Column("Email")]和[MaxLength(255)]共同作用的效果。


更詳細的信息,請參考http://msdn.microsoft.com/en-us/data/jj819164.aspx


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM