我有一个包含5个独立表的Entity Framework项目。当我从这些表中查询数据并使用.Include()
时,它生成的查询非常慢并且超时。
我已将查询移至存储过程,现在正在寻找查询此存储过程的方法,并轻松将其返回的数据映射到现有数据类。
我对EF的DataContext的原始Linq查询如下所示:
var data = (from a in context.A
.Include("B")
.Include("C")
.Include("D")
.Include("E")
where a.Id == someValue
select a);
它返回一个类似于此的实体数据对象:
class A
{
int Id;
string otherProperties;
List<B> B;
List<C> C;
List<D> D;
List<E> E;
}
EF生成在SQL服务器上运行的查询返回的结果集如下所示:
C1 C2 C3 C4 C5 C6 C7 C8 C9 C10 ---------------------------------------------------------- A1 A2 B1 B2 A1 A2 C1 C2 A1 A2 C1 C2 A1 A2 C1 C2 A1 A2 D1 D2 A1 A2 D1 D2 A1 A2 D1 D2 A1 A2 E1 E2 A1 A2 E1 E2
(假设1 B记录,3 C记录,3 D记录和2 E记录。
我在存储过程中重现了这个查询,并将其运行时减少到几乎没有,但是我仍然试图弄清楚如何将结果集映射到我的Entity Framework数据类(上面的类A
)。
EF肯定能够做到这一点,因为当我使用Linq查询时它已经在幕后的某个地方,但我不确定这是否是我可以访问的内容。
在Entity Framework中有一种简单的方法可以将单个存储过程(Function Import)映射到多级Entity Framework类吗?
答案 0 :(得分:2)
我发现了一篇博文,解释了如何使用Entity Framework完成此任务。
总结一下,您需要编写存储过程,以便它以Entity Framework所期望的特定方式返回数据,然后您可以使用一些EF extensions来自定义存储过程执行,并且实现对象图。
在未来的版本(我相信5.0+)中看起来这是内置于Entity Framework中的,但是这种解决方法看起来应该适用于较低版本。
虽然在我的情况下,我发现如果我在Linq查询中删除.Include()
并通过在返回对象之前在代码中引用它们来手动触发加载其他属性,我的性能问题得到修复。这是因为它不是在具有未优化连接的5个表之间构建一个大规模查询,而是运行5个单独的查询,每个查询仅提取所需的特定数据。
答案 1 :(得分:1)
当我通过将昂贵的查询转换为storedprocedure来优化EntityFramework时,我为结果创建了一个自定义类,然后在DbContext中执行一些逻辑将我的自定义类转换为实体。
所以你要创建像
这样的东西public class StoreProcARow
{
public string Name {get;set;} // properties for every column
}
然后在DbContext
public A GetA(int ID)
{
// do stored procedure
IEnumerable<StoreProcARow> procResult = ...
// process procResult into A type
}
答案 2 :(得分:0)
尝试AutoMapper。
你会做类似的事情:
using AutoMapper;
...
Mapper.CreateMap<DataModel.B, ReplyObjects.B>;
Mapper.CreateMap<DataModel.C, ReplyObjects.C>;
...
return new A
{
B = Mapper.Map<DataModel.B, ReplyObjects.B>(varContainingDataForB),
C = Mapper.Map<DataModel.C, ReplyObjects.C>(varContainingDataForC)
...
};
只要ReplyObjects.B中的属性与DataModel.B的名称和类型相匹配,一切都会自动映射!