8

我有一个包含 5 个单独表的实体框架项目。当我从这些表中查询数据并使用.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 Server 上运行的查询返回的结果集如下所示:

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 记录。

我已经在一个存储过程中重现了这个查询,并将它的运行时间减少到几乎没有,但是我一直在试图弄清楚如何将结果集映射到我的实体框架数据类(A上面的类)。

EF 绝对能够做到这一点,因为当我使用 Linq 查询时它已经在幕后某处做到了,但我不确定这是否是我可以访问的东西。

实体框架中是否有一种简单的方法可以将单个存储过程(函数导入)映射到多级实体框架类?

4

3 回答 3

2

我找到了一篇博客文章,解释了如何使用 Entity Framework 完成此操作。

http://blogs.infosupport.com/ado-net-entity-framework-advanced-scenarios-working-with-stored-procedures-that-return-multiple-resultsets/

简而言之,您需要编写存储过程,以便它以实体框架所期望的特定方式返回您的数据,然后您可以使用一些EF 扩展来自定义您的存储过程执行,并具体化您的对象图。

看起来这在未来版本(我相信 5.0+)中内置于实体框架中,但是这种解决方法看起来应该适用于较低版本。

尽管在我的情况下,我发现如果我刚刚摆脱了.Include()Linq 查询中的 并通过在返回对象之前在代码中引用它们来手动触发加载其他属性,我的性能问题得到了解决。这是因为它不是在 5 个未优化连接的表之间构建一个大规模查询,而是运行 5 个单独的查询,每个查询只提取它需要的特定数据。

于 2013-01-18T15:27:28.630 回答
1

当我通过将昂贵的查询转换为存储过程来优化 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

}
于 2013-01-17T18:02:43.893 回答
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 的名称和类型相匹配,一切都会自动映射!

于 2013-01-17T18:11:49.633 回答