【发布时间】:2019-03-16 21:48:51
【问题描述】:
我正在尝试使用IQueryable GroupJoin 一些数据并将该数据投影到匿名类型中。我 GroupJoining 进入的原始实体具有 ICollection 导航属性(即一:多)。我想急切地加载该属性,以便在组加入后访问它,而无需 EF 返回数据库。我知道当你使用GroupJoin 时Include() 不起作用,但下面的代码是我发现让它急切加载集合的唯一方法(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 急切加载导航属性?
注意:我想使用导航属性而不是将其投影到匿名类型的新属性中,因为 AutoMapper 想要在映射到 DTO 对象时访问 Room.ContactRoomRoles。
【问题讨论】:
-
我觉得你在使用 ORM 的同时抱怨代码看起来很hacky,这很有趣。如果你想看到一些丑陋的代码,你应该对数据库进行跟踪并查看它生成的 SQL 代码!
-
如果您这样做只是为了获得 AutoMapper 生成的 DTO 图,为什么不让 AutoMapper 使用可查询扩展功能作为查询的一部分为您进行投影? docs.automapper.org/en/stable/Queryable-Extensions.html
-
非 hacky 方法是定义和使用正确的导航属性而不是
GroupJoin。 EF 中的任何手动连接都表明实体模型不正确。在您的情况下,ContactRoomRole实体应具有指向Contact的导航属性,表示CreatedByFK。 -
@IvanStoev 实际查询更复杂,需要组加入,因为我有一个要加入的子查询。这个例子只是简化了。
-
那么可能会提供更现实的例子。急切加载的规则很明确 - 请参阅 stackoverflow.com/questions/52767559/…。您在当前示例中使用的内容称为在查询返回内存中的实体的具体化过程中的跟踪和导航属性修复。
标签: c# sql-server database entity-framework