转自:http://www.cnblogs.com/richwong/archive/2011/07/06/2098759.html

最近的项目开始使用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了。

(转)自己来控制EntityFramework4.1 Code-First,逐步消除EF之怪异现象的更多相关文章

  1. 2.简单的Code First例子(EF Code-First系列)

    现在假想,我们想要为讴歌学校创建一个应用程序,这个程序需要能够来添加或者更新学生,分数,教师还有课程信息. 代替之前我们的做法:先是创建数据库,现在我们不这么做,我们先来创建领域类,首先我来创建两个简 ...

  2. 【繁星Code】如何在EF将实体注释写入数据库中

    最近在项目中需要把各个字段的释义写到数据库中,该项目已经上线很长时间了,数据库中的字段没有上千也有上百个,要是一个项目一个项目打开然后再去找对应字段查看什么意思,估计要到明年过年了.由于项目中使用En ...

  3. Code Review 程序员的寄望与哀伤

    一个程序员,他写完了代码,在测试环境通过了测试,然后他把它发布到了线上生产环境,但很快就发现在生产环境上出了问题,有潜在的 bug. 事后分析,是生产环境的一些微妙差异,使得这种 bug 场景在线下测 ...

  4. Code First :使用Entity. Framework编程(8) ----转发 收藏

    第8章 Code First将走向哪里? So far, this book has covered all of the Code First components that reached the ...

  5. Code First :使用Entity. Framework编程(6) ----转发 收藏

    Chapter6 Controlling Database Location,Creation Process, and Seed Data 第6章 控制数据库位置,创建过程和种子数据 In prev ...

  6. EntityFramework Reverse POCO Code First 生成器

    功能强大的(免费)实体框架工具 Julie Lerman 实体框架是开源的,因此开发社区可以在 entityframework.codeplex.com 上共享代码. 但是不要将自己局限在那里寻找工具 ...

  7. NK3C 业务权限控制

    资源中,添加了一个类型:权限(橙色显示),现在有4种数据: 域管理员:domainAdmin 组织管理员:orgAdmin 组管理员:groupAdmin 一线员工:phoneAdmin 权限控制可以 ...

  8. EF Code First学习笔记:数据库创建

    控制数据库的位置 默认情况下,数据库是创建在localhost\SQLEXPRESS服务器上,并且默认的数据库名为命名空间+context类名,例如我们前面的BreakAway.BreakAwayCo ...

  9. spring2.5IOC控制反转详解

    spring2.5IOC控制反转详解 19. 五 / J2EE / 一条评论   基本的代码结构 1 IOC包下 基本的spring创建对象 将类添加到配置文件中,由容器创建. Source code ...

随机推荐

  1. linux高级编程——IO

    1,文件IO 1)open——打开或创建一个文件 open(char *,flag,mode)在fcntl.h文件中声明. 参数: char * 包含有文件名和路径 flag 打开文件方式 mode ...

  2. 基础数据类型补充,及capy daty7

    1,基础数据类型,总结补充. int:bit_lenth() str: captilze() 首字母大写,其余小写. upper() 全大写. lower() 全小写. find() 通过元素找索引, ...

  3. Vue 快速原型开发

    快速原型开发 注意: 是:serve 而不是 server 通过使用 vue serve 和 vue build 命令对单个 *.vue 文件进行快速原型开发,不过这需要先额外安装一个全局的扩展 go ...

  4. Oracle性能优化5-索引的不足

    索引的不足 1.索引开销 a.访问开销   反问集中导致热块的竞争(对最新数据的查询)   回表性能取决聚合因子   索引的访问开销,返回几条数据快,但是返回大量的数据很慢   全表扫描与全扫描   ...

  5. Oracle_PL/SQL(6) 触发器(序列、视图)

    序列1.创建序列create sequence seq_alog start with 1 increment by 1 maxvalue 999999999999999999999999999 mi ...

  6. Oracle的SQL语句中如何处理‘&’符号

    ‘&’符号在SQL中有特殊含义,所以在SQL中想要写入&,需要特殊处理. 如下SQL语句就不能正确运行: SQL> select 'a&b' from dual; 处理方 ...

  7. PHP——explode的应用(获取字符串,拆为下拉列表)

    <?php //定义有默认值的函数 function Main3($f=5,$g=6) { echo $f*$g; } Main3(2,3); echo "<br />&q ...

  8. MySql数据库 sql查询增加序号的伪列

    在查询数据库的时候,我们有时候需要对查询出来的数据加上序列,1,2,3,……n 例如:我们根据表的某个字段排序后,要对这些数据加上序列,这个时候序号常常不是我们建表时设置好的自增的主键id,怎么办呢? ...

  9. TCHAR函数查询

    https://blog.csdn.net/is2120/article/details/27542927

  10. Python之路(第二十一篇) re模块

    一.re模块 正则表达式本身是一种小型的.高度专业化的编程语言,正则表达式就是字符串的匹配规则,在多数编程语言里都有相应的支持,python里对应的模块是re,正则表达式模式被编译成一系列的字节码,然 ...