自己来控制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了。
自己来控制EntityFramework4.1 Code-First,逐步消除EF之怪异现象相关推荐
- 如何在团队中做好Code Review
一.Code Review的好处 想要做好Code Review,必须让参与的工程师充分认识到Code Review的好处 1.互相学习,彼此成就 无论是高手云集的架构师团队,还是以CURD为主的业务 ...
- EF Code First学习笔记:数据库创建(转)
控制数据库的位置 默认情况下,数据库是创建在localhost\SQLEXPRESS服务器上,并且默认的数据库名为命名空间+context类名,例如我们前面的BreakAway.BreakAwayCo ...
- Code First :使用Entity. Framework编程(6) ----转发 收藏
Chapter6 Controlling Database Location,Creation Process, and Seed Data 第6章 控制数据库位置,创建过程和种子数据 In prev ...
- Visual Studio Code(VS Code)与Git Source Control集成
This article explores Visual Studio Code integration with Git Source Control. 本文探讨了Visual Studio Cod ...
- Notes Twelfth Day-渗透攻击-红队-命令与控制
** Notes Twelfth Day-渗透攻击-红队-打入内网(dayu) ** 作者:大余 时间:2020-09-28 请注意:对于所有笔记中复现的这些终端或者服务器,都是自行搭建的环境进行渗透 ...
- 自动驾驶车辆控制测评标准
自动驾驶中,车辆控制是基础,以什么指标来测评就显的很关键,以下是Apollo 车辆控制评测分析指标,可以在此基础上做裁剪,来满足自己自动驾驶车辆控制的需求. 序号 参数 名称 说明 平均控制性能相关参 ...
- STM32CubeIDE 统计及控制PWM产生个数
STM32 HAL库有两个PWM中断回调函数 void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim) : PWM脉冲在非阻塞模式 ...
- 应用8255A控制LED小灯开闭(附代码注释)
设8255A的A口和B口都工作在方式0,A口作为输出口,接有8个开关;B口为输出口,接有8个发光二极管.系统硬件电路中不断扫描开关Ki,当K0闭合时,点亮LED0,LED2,LED4,LED6,其他L ...
- 单片机自动调光C语言,基于51单片机的DS18B20水温PID控制调节系统设计C语言程序...
#include 'reg52.h' #include 'stdio.h' #define uchar unsigned char #define uint unsigned int sbit s1= ...
- python控制灯泡_人工智能应用-手把手教你用Python硬件编程实现打开或关闭电灯泡...
之前我们已经给广大爱好者或程序员朋友们,带来了硬件版的或者说物联网版本的Hello World C++Builder版.Delphi.Visual Basic.Net等的程序源码和教学资料,让大家对硬 ...
最新文章
- 翻译BonoboService官网的安装教程
- leetcode算法题--最长快乐字符串★
- JSP(1)—基础知识
- angular中的依赖注入
- 星空下的痕迹 Jenkins学习(四)----------windows下Publish over FTP插件应用
- matlab数字滤波器设计函数汇总(转载)
- html5内容切换特效,html5+jQuery图片和文字内容同时左右切换特效
- POJ 3608 Bridge Across Islands 《挑战程序设计竞赛》
- SpringCloudGateway 集成 nacos 整合实现动态路由_04
- MCSE2003学习之八
- java的继承关系linkedlist_LinkedList——JAVA成长之路
- vue实现对数据的增删改查(CURD)
- 如何给一家公司做定性研究?
- WEB环境下打印报表的CRYSTAL的解决方案
- 直播网站源码,简洁的登录页面
- 指数族分布(2):矩母函数、累积量生成函数
- 第十届全国大学生GIS应用技能大赛上午(试题及参考答案)
- 4K分辨率是什么 你真的知道吗?
- numpy_abs和fabs
- PgSql之操作JSON类型字段