作者:涵宝宝201503 | 来源:互联网 | 2022-12-02 14:51
我正在尝试使用GroupJoin
一些数据IQueryable
并将数据投影为匿名类型.我所在的原始实体GroupJoin
具有ICollection
导航属性(即一个:多个).我想急切加载该属性,以便我可以在组加入后访问它而不用EF返回到数据库.我知道Include()
当你使用a时它不起作用GroupJoin
,但是下面的代码是我发现的唯一方法,使它急于加载collection(ContactRoomRoles
):
using (var cOntext= new MyDbContext()) {
var foundRooms = context.Rooms.Include(rm => rm.ContactRoomRoles);
foundRooms.ToList(); // <-- Required to make EF actually load ContactRoomRoles data!
var roomsData = foundRooms
.GroupJoin(
context.Contacts,
rm => rm.CreatedBy,
cOnt=> cont.Id,
(rm, createdBy) => new {
COntactRoomRoles= rm.ContactRoomRoles,
Room = rm,
CreatedBy = createdBy.FirstOrDefault()
}
)
.ToList();
var numberOfRoles1 = roomsData.ElementAt(1).Room.ContactRoomRoles.Count();
var numberOfRoles2 = roomsData.ElementAt(2).Room.ContactRoomRoles.Count();
var numberOfRoles3 = roomsData.ElementAt(3).Room.ContactRoomRoles.Count();
}
如果我删除了foundRooms.ToList()
,EF会在数据库中进行3次以填充我的numberOfRoles
变量,但foundRooms.ToList()
事实并非如此 - 它只是急于在一个查询中预先加载数据.
虽然这有效,但感觉就像完全黑客.我只是要求.ToList()
让EF实际加载收集数据的副作用.如果我评论该行,它会在我尝试访问时进入数据库ContactRoomRoles
.是否有一种不太常见的方式使EF eager加载导航属性?
注意:我想使用导航属性而不是将其投影到匿名类型的新属性中,因为AutoMapper Room.ContactRoomRoles
在映射到DTO对象时想要访问它.
1> Roman Pokrov..:
这不是一个黑客.这是一个抽象泄漏.我们应该准备好使用ORM工具(以及任何其他内部DSL)来解决抽象泄漏问题.
在ToList()
你不仅执行实际的sql调用(并将数据加载到内存中)之后,还要交叉到其他Linq风格 - "Linq for objects".在此之后所有的调用Count()
都不会因为你开始使用内存集合而生成sql(而不是表达式树被隐藏的IQueryable
- GroupBy
语句的返回类型,但带有List
集合 - 返回类型的ToList).
如果没有ToList()
你留下"Linq for sql",EF会将Count()
IQuerybale上的每次调用转换成sql; 三个Conut()调用=三个带下划线的Sql语句.
没有办法避免这种情况,否则count(*)
在一个复杂查询中计算服务器端的所有值.如果您将尝试使用Linq(构建expression tree
)编写此类查询- 您将再次遇到抽象泄漏.ORM工具旨在将对象映射到"RDBS实体",保持CRUD(创建读取更新删除)操作 - 如果语句变得更复杂 - 您将无法预见生成的sql(以及所有运行时异常,如'无法生成sql对于这样的linq').因此,不要将linq用于复杂的"报告",例如"查询"(在某些情况下,您可以 - 这取决于您的重复使用要求和测试可能性).使用旧的好SQL并通过ADO或EF ADO"sql扩展"调用它,如EF Core FromSql
:
var blogs = context.Blogs
.FromSql("EXECUTE dbo.GetMostPopularBlogsForUser {0}", user)
.ToList();
更新:如果您不使用可重复使用的EF工具,建议您避免使用延迟加载和手动实体加载.它们在某种意义上与linq查询相反 - 表达式树.它们是重要的(如果不是只有一个)选项,用于在"旧"平台上加载引用的实体,其中语言中没有"表达式树",但在.NET/EF中,完整查询可以"声明方式"写为表达式树而不执行(但推迟解释)应该有非常强烈的理由返回"手动"加载.