Entity Framework快速入门--一对零到一关系处理

简介: 很久不更新blog了,正好趁着端午节的空,把之前一段时间使用关于EF以及工作上经验总结一下。 此文将跟朋友们分享一下关于1对0..1实体模型一些使用包括基本的添加和查询的注意事项。 首先我们EDMX实体模型: 模型很简单,一个用户的实体,另外关联了一个用户信息的实体。

很久不更新blog了,正好趁着端午节的空,把之前一段时间使用关于EF以及工作上经验总结一下。

此文将跟朋友们分享一下关于1对0..1实体模型一些使用包括基本的添加和查询的注意事项。

首先我们EDMX实体模型:

img_ca0ebefe7be924ec278d1af7351c4702.png

模型很简单,一个用户的实体,另外关联了一个用户信息的实体。有些情况下我们会有这样的需求,用户登录身份验证,而每次再查询用户信息的时候,往往会去查询用户表,而这时候我们仅仅使用了2-3个字段也就是用户账号跟密码是否一致,如果一致就返回true,否则返回false,而我们往往在用户表上挂在很多的其他字段,这样就造成了无谓的性能损失。当然如果访问量很小的话,那也无所谓了。  有时候我们会把一些可以为null或者经常不使用的字段放到一张UserInfo表中,而频繁访问和验证的用户表单独出一个小的表,用于专门来进行身份验证等业务。如上图EDMX的设计,当然只是一个模拟的例子。

根据这个1对0到1的关系,我们自己猜一下也能想到,那就我们在进行将用户信息持久化到数据库时,用户信息表实体(UserInfo)必须挂在到一个User实体上才能持久化到数据库。而User表不受UserInfo表的影响,可以单独插入一条数据。看下面代码都是可以正确执行:

单独插入User实体数据:

 
 
static void InsertData()
{
using (CompanyContainer companyContainer = new CompanyContainer())
{
User user
= new User();
user.Code
= " flydragon " ;
user.Name
= " 飞龙天惊 " ;
user.Password
= " haha " ;
companyContainer.User.AddObject(user);
companyContainer.SaveChanges();
}
}

我们也可以同时保存一个整体的数据,如下代码所示:插入User+UserInf实体两个数据

 
 
static void InsertFullData()
{
using (CompanyContainer companyContainer = new CompanyContainer())
{
User user
= new User();
user.Code
= " flydragon3 " ;
user.Name
= " 飞龙天惊3 " ;
user.Password
= " haha3 " ;
companyContainer.User.AddObject(user);

UserInfo userInfo
= new UserInfo();
userInfo.Email
= " malun666@hotmail.com " ;
userInfo.Address
= " 北京上地 " ;
userInfo.Phone
= " 110 " ;
userInfo.User
= user;
userInfo.Rmark
= "" ;
companyContainer.UserInfo.AddObject(userInfo);
companyContainer.SaveChanges();
}
}

上面没什么好说的,也没什么好主意的点。当然在项目中还是遇到了很多细节的问题。当然比较头疼的一个问题就是1对0...1关系模型数据的查询异常的BUG。我们在查询User实体数据的时候,EF帮我们生成的SQL脚本却自动的帮我们对UserInfo表进行Left Out Join。很多情况我们只检索了User表的数据,却也进行了Join的操作,这样使我们本来为了提高用户表数据查询的效率反而进行了Join,数据量成了两个表的笛卡尔积的结果里进行查询,这样效果肯定不好。看下面代码以及SqlProfile追踪到的SQL:

 
 
static void Main( string [] args)
{
CompanyContainer companyContainer
= new CompanyContainer();
var result
= companyContainer.User.Where < User > (u => u.Code == " flydragon3 " )
.Where
< User > (u => u.Password == " haha3 " )
.FirstOrDefault
< User > ();
if (result != null )
{
Console.WriteLine(result.Name);
}
Console.ReadKey();
}

下面是用SQLProfile工具追踪到的执行的SQL脚本:

img_09261e782fa6017fdaf36a7822a4761c.png

很明显我们看到的是有User表和UserInfo表的Join操作。我猜测EF内部实现的细节可能是初始化User实体的时,由于导航属性UserInfo的关系是1 对0..1做了特殊处理,也将UserInfo的数据取出来初始化了导航属性UserInfo。

这个需要大家使用EF时候一定注意这个细节。

那我们怎样避免这样的结果呢:

下面几种方式是可以杜绝这种外连接的:

如:

 
 
static void Main( string [] args)
{
CompanyContainer companyContainer
= new CompanyContainer();
var result
= companyContainer.User.Where < User > (u => u.Code == " flydragon3 " )
.Where
< User > (u => u.Password == " haha3 " ).Count();
Console.WriteLine(result);
Console.ReadKey();
}

对应产生的SQL为:

 
 
SELECT
[ GroupBy1 ] . [ A1 ] AS [ C1 ]
FROM ( SELECT
COUNT ( 1 ) AS [ A1 ]
FROM [ dbo ] . [ User ] AS [ Extent1 ]
WHERE (N ' flydragon3 ' = [ Extent1 ] . [ Code ] ) AND (N ' haha3 ' = [ Extent1 ] . [ Password ] )
)
AS [ GroupBy1 ]

另外怎么只查询User,并将User表的几个字段取出方法如下:

 
 
static void Main(string [] args)
{
CompanyContainer companyContainer
= new CompanyContainer();
var result = companyContainer. User . Where < User > (u => u.Code == "flydragon3")
.
Where < User > (u => u.Password == "haha3")
.
Select (u => new { Id = u.Id,Name = u.Name }).FirstOrDefault();
if (result != null )
{
Console.WriteLine(result.Name);
}
Console.ReadKey();
}

最终生成的SQL脚本为:

 
 
SELECT TOP ( 1 )
[ Extent1 ] . [ Id ] AS [ Id ] ,
[ Extent1 ] . [ Name ] AS [ Name ]
FROM [ dbo ] . [ User ] AS [ Extent1 ]
WHERE (N ' flydragon3 ' = [ Extent1 ] . [ Code ] ) AND (N ' haha3 ' = [ Extent1 ] . [ Password ] )

暂时总结到这里,写文章真是费时费力!希望大家都分享自己的知识,大家一起交流一起进步!祝大家端午快乐!

Entity Framework快速入门--索引贴

目录
相关文章
|
3月前
|
存储 数据库 开发者
深入浅出讲解Entity Framework Core中的复杂类型与值对象:从理论到实践的全方位指南,附带详实代码示例与最佳应用技巧
【8月更文挑战第31天】本文通过教程形式详细介绍了如何在 Entity Framework Core 中使用复杂类型与值对象,帮助开发者更自然地映射实体和数据库间的关系。文章首先指导创建基于 EF Core 的项目,并添加相关 NuGet 包。接着,通过具体代码示例展示了如何配置数据库上下文、定义领域模型,并使用复杂类型与值对象进行数据存储和查询。最后总结了使用这些技术的优势,包括简化复杂数据结构映射、提高可维护性及数据一致性。
48 0
|
XML 安全 前端开发
odoo 开发入门教程系列-模型之间的关系(Relations Between Models)
odoo 开发入门教程系列-模型之间的关系(Relations Between Models)
149 0
|
存储 运维 Dubbo
Dubbo3 源码解读-宋小生-3:框架,应用程序,模块领域模型Model对象的初始化
> Dubbo3 已经全面取代 HSF2 成为阿里的下一代服务框架,2022 双 11 基于 Dubbo3 首次实现了关键业务不停推、不降级的全面用户体验提升,从技术上,大幅提高研发与运维效率的同时地址推送等关键资源利用率提升超 40%,基于三位一体的开源中间件体系打造了阿里在云上的单元化最佳实践和统一标准,同时将规模化实践经验与技术创新贡献开源社区,极大的推动了开源技术与标准的发展。 > 本文
483 0
Dubbo3 源码解读-宋小生-3:框架,应用程序,模块领域模型Model对象的初始化
|
存储 算法 JavaScript
Go 语言快速入门指南:第六篇 与数据为舞之映射
在我们学习汉字的时候,发现有一个生僻字的话,我们会使用字典。字典这种数据组织方式就是为了方便查询的操作的,那么 Go 语言中有没有这样的方式来存储数据呢?当然是有,maps。
|
缓存
FastAPI 学习之路(二十四)子依赖项
FastAPI 学习之路(二十四)子依赖项
FastAPI 学习之路(二十四)子依赖项
|
索引 Python
第三章--第三节:列表
第三章--第三节:列表
153 0
第三章--第三节:列表
|
存储 文件存储
【1】JAVA---地址App小软件(AddressApp.class)(初步接触项目开发的分层思想)(表现层)
【1】JAVA---地址App小软件(AddressApp.class)(初步接触项目开发的分层思想)(表现层)
395 0
|
安全 Java Maven
【教程】如何利用MapStruct 解决对象之间转换问题(一)
本篇文章主要用于记录自己整理的MapStruct使用教程。
【教程】如何利用MapStruct 解决对象之间转换问题(一)
|
Python
第四章--第二节:类
第四章--第二节:类
106 0