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)]共同作用的效果。

优质内容筛选与推荐>>
1、MQTT 5.0 正式成为OASIS标准
2、C开发系列-指针
3、leetcode 1004. 最大连续1的个数 III(Max Consecutive Ones III)
4、2016HUAS_ACM暑假集训3B - Frogger
5、Android 去除状态栏和隐藏虚拟按键


长按二维码向我转账

受苹果公司新规定影响,微信 iOS 版的赞赏功能被关闭,可通过二维码转账支持公众号。

    阅读
    好看
    已推荐到看一看
    你的朋友可以在“发现”-“看一看”看到你认为好看的文章。
    已取消,“好看”想法已同步删除
    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送

    已发送

    朋友将在看一看看到

    确定
    分享你的想法...
    取消

    分享想法到看一看

    确定
    最多200字,当前共

    发送中

    网络异常,请稍后重试

    微信扫一扫
    关注该公众号





    联系我们

    欢迎来到TinyMind。

    关于TinyMind的内容或商务合作、网站建议,举报不良信息等均可联系我们。

    TinyMind客服邮箱:support@tinymind.net.cn