[已更新 - 请参阅底部的更新]
我首先使用的是EF代码,我对它很满意。但是,一个简单(和常见)的操作导致EF生成可疑的复杂SQL,这会减慢我的应用程序。
我只是使用(整数)ID列表来获取一组实体,但是因为我需要许多子实体的详细信息,所以我使用.Include()
来获取在那里加载的子实体同时,如下:
db.MyEntities
.Where(x => x.ClientId == clientId)
.Where(x => ids.Contains(x.Id))
.Where(x => x.SubEntity1 != null)
.Include(x => x.SubEntity1)
.Include(x => x.SubEntity1.SubSubEntity1)
.Include(x => x.SubEntity1.SubSubEntity2)
.Include(x => x.SubEntity1.SubSubEntity3)
.Include(x => x.SubEntity1.SubSubEntity4)
.Include(x => x.SubEntity2)
.Include(x => x.SubEntity2.SubSubEntity1)
.Include(x => x.SubEntity2.SubSubEntity2)
.Include(x => x.SubEntity2.SubSubEntity3)
.Include(x => x.SubEntity2.SubSubEntity4)
.Include(x => x.SubEntity3)
正如您所看到的,除了所有Include
之外,它不是一个特别复杂的查询。
EF为此生成的SQL 巨大 - 围绕 74Kb 的SQL。执行不需要很长时间(因为通常ID列表中的项目数量很少),但只需构建查询就需要EF 一秒钟 - 即查询之前甚至被发送到数据库。
如果我删除Includes
,那么查询要小得多,而且整个过程花费的时间要少得多 - 但是各个相关的实体会一次一个地加载,这不会扩展好。
EF似乎给了我两个加载数据的选项:
Include
)或Load
/ LoadProperty
)。选项1将是我的首选选项,如果它有效,但由于在这种情况下不起作用,我唯一剩下的选项是2 - 我不认为这是可以接受的:会有太多的数据库查询输入ID列表(即实体数量)很大。
在我看来,EF似乎还没有解决另一个选择:获取主要实体,获取所有相关的SubEntity1实体,然后获取所有相关的SubEntity2实体等。这样,查询数量与要获取的实体的类型的数量有关,而与实体的数量有关。这样可以更好地扩展。
我无法在EF中看到这样做的方法:换句话说,就是说“为所有这些实体加载此属性(在单个查询中)”。
我是否只需要放弃EF并编写自己的SQL?
更新
我注意到即使我删除了Include
,生成的SQL也比我想象的要复杂得多,而且我认为这都源于EF不喜欢我的表结构这一事实。我花了好几天的时间让EF通过Code First(以及Fluent API)创建我想要的数据库结构,即使我必须(几乎)到达我想要的地方,我也不得不接受一些妥协。 / p>
我想我现在因为敢于做一些EF不希望我这样做的事而付出进一步的惩罚。它看起来像一个简单的查询比它应该更复杂,而稍微复杂一点的查询要复杂得多。
令人难以置信的令人沮丧 - 我以为我已经把所有那些EF麻烦都抛在后面了,而且这个系统现在正在生产中,有很多用户 - 这将使我很难重新开始。
似乎我将不得不花费永恒的力量与EF牙齿和指甲搏斗。我多么希望我从来没有使用过它!
无论如何,回到我原来的问题:如果我有一堆A类实体,我想在一个查询中加载类型B 的相关子实体,有没有办法这样做?
答案 0 :(得分:3)
如何使用存储过程加载数据?是的,它有点脏,但是当我遇到EF的性能问题时,这就是我所做的。我希望你的问题不会丢失。