自己来控制EntityFramework4.1 Code-First,逐步消除EF之怪异现象

最近的项目开始使用EF4.1,拜读各路大侠文章数遍,满以为可以轻车熟路,却屡遭悲惨啊,怪异现象接连...

1,虽然使用Code-First模式,就是因为它代码整洁清爽条理,但还是习惯先建立数据表,再POCO...  结果发现Entity实体类与数据表的映射是EF自己独特智能操控的,比如实体类名为Product,它会智能映射成Products的表,加了个"s",然而,Category的实体类却映射成了Categories, 它居然能识别单词的复数写法,很神奇,难道它内置词典?要不然它该映射成Categorys才合理嘛(虽然它不是个单词),你说EF神奇么,真神奇!

后来,同事给个方法,解决了这个神奇的功能,我要自控,有些关键地方不需要EF来控制我的想法,于是在分类名上面添加一个特性[Table("映射的表名")]即可。

[Table( "Product" )]
public  class  Product
{
     public  int  ID { get ; set ; }
     [Required]
     [Display(Name = "产品名" )]
     public  string  Name { get ; set ; }
     public  int  CategoryID { get ; set ; }
     [Required]
     [Display(Name = "产品价格" )]
     public  Decimal? Price { get ; set ; }
 
     public  virtual  Category Category { get ; set ; }
}
 
[Table( "Category" )]
public  class  Category
{
     public  int  CategoryID { get ; set ; }
     /// <summary>
     /// 分类名
     /// </summary>
     [Required]
     [Display(Name = "分类名" )]
     public  string  CategoryName { get ; set ; }
     public  Int16 IsDel { get ; set ; }
     public  virtual  ICollection<Product> Products { get ; set ; }
}

我后来又发现一个终极解决办法,那就是在Model建立的时候,移除EF内部的约定,神奇的约定

protected  override  void  OnModelCreating(DbModelBuilder modelBuilder)
{
     // base.OnModelCreating(modelBuilder);  
     // modelBuilder.Entity<Order>().ToTable("Order"); 和实体类名的Table特性设置相同
 
     // 移除EF的表名公约 
     modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
     // 还可以移除对MetaData表的查询验证
     modelBuilder.Conventions.Remove<IncludeMetadataConvention>();
 
}

2,每次通过EF查询数据库,会先Select ... MetaData,甚至SELECT Count(*) FROM sys.databases WHERE [name]=数据库名,前者的无用查询移除,在上面的OnModelCreating中可以取消了,但后者至今我还没找到办法。可以理解的是:EF之code-first会先查找数据库,如果没有则建立命名空间.CustomContext的库名,所以多了后者的查询,即便我在DbContext的类初始化中指定db名、或者连接字符串名,也是同样结果。而实体类和数据表是映射的,EF将实体类做了Hash计算以比对数据表,当发现实体类与数据表不对应的时候,会更新数据表,故而增加了查询metaData的动作。 其实对于我们固定的开发需求,这些功能,不能被关闭实在消耗性能。

3,EF是默认开启延迟加载,延迟加载的关系表中,必须建立表关系,也就是SQL的FK键。延迟加载非常好用,但存在性能问题,因为延迟加载关联到几个表,就要执行几次数据表查询,而不是一次性查询。这也是从字义上理解的达到一致。否则就属于贪婪加载,即Context上下文里的Include("实体名"),可以实现一次性一条SQL语句查询,但我奇怪的是Include的string参数为啥不是表名,反而是实体名却用字符串来传入。

4,最痛苦的是EF下实体类或表字段外键,命名中不能有"_"?经过我测试也不尽然,虽然我发觉到了这是和关联表定义有关系,可是我仍非常不解,例如:

[Table( "Product" )]
public  class  Product
{
     public  int  ID { get ; set ; }
     [Required]
     [Display(Name = "产品名" )]
     public  string  Name { get ; set ; }
     public  int  CategoryID { get ; set ; }
     [Required]
     [Display(Name = "产品价格" )]
     public  Decimal? Price { get ; set ; }
 
     public  virtual  Category Category { get ; set ; }
}
 
[Table( "Order" )]
public  class  Order
{
     [Key]
     public  int  ID { get ; set ; }
     public  int  Product_ID { get ; set ; }
     public  string  Name { get ; set ; }
     public  string  Address { get ; set ; }
     public  DateTime CreateTime { get ; set ; }
     public  virtual  Product Product { get ; set ; }
}

这是一对关系表,显然设计的是一张订单中只有一个产品,订单中的Product_ID属性对应产品实体的ID属性,已经在数据库中做好了关系。 我要的结果是:当打开一条订单记录时,联表查询得到该产品ID的产品信息,所以做了延时加载public virtual Product Product { get; set; }

非常怪异的现象是,执行Order实体上下文ToList等操作时,提示Product_ID1列不存在,因为这个字段和属性的确不存在,为什么EF会拼出这个字段来呢? 之所以说不尽然是"_"的原因,因为即使我将属性和字段修改成ProductsID,EF却又报错找不到Product_ID的字段,EF要找的这2个字段本身都不存在。它为什么呢? 只有当这个外键字段为ProductID时才正常,这个非常诡异!!! 慢慢我发现,是public virtual Product Product { get; set; } 这个属性,生成了外键ID对应关系的字段Product_ID,也就是EF自己用了"_"符号,但当写成ProductID时,又没有生成。。。很糊涂。。。

5,继续实验中

总结,EF用起来比较轻松,但掌握住还是比较费劲的,虽说EF把一切都封装好了,但了解它的内幕才能给自己更多的信心,至少目前还不能掌握,还不能控制,总是被EF控制,这并不是什么好事,继续努力!如果你有这方面的知识,分享下吧 :)

补充第4条的“怪异现象”,直接见代码:

[Table( "Order" )]
public  class  Order
{
     [Key]
     public  int  ID { get ; set ; }
     public  int  Product_ID { get ; set ; }
     public  string  Name { get ; set ; }
     public  string  Address { get ; set ; }
     public  DateTime CreateTime { get ; set ; }
 
     [ForeignKey( "Product_ID" )]  //增加一个外键特性,并制定外键字段 
     public  virtual  Product Product { get ; set ; }
}

Product_ID是外键字段,关联了Product属性,因为Product的主键是ID,EF自己拼装了一个外键字段为“Product_ID”,所以与实际的字段重复,重命名了“Product_ID1”;而当外键属性为其他时,EF就会自己拼装一个“Product_ID”,所以会找不到这个列;但是当属性为ProductID时,EF不会去拼装外键字段,这一定又是EF的内部约定。所幸的是,现在我可以给Product关联的导航属性一个外键特性就OK了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值