我正在将我的EF linq查询更改为存储过程。有没有简单的方法来设置复杂的映射?

时间:2013-01-17 17:51:37

标签: c# entity-framework entity-framework-4

我有一个包含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类吗?

3 个答案:

答案 0 :(得分:2)

我发现了一篇博文,解释了如何使用Entity Framework完成此任务。

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

总结一下,您需要编写存储过程,以便它以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的名称和类型相匹配,一切都会自动映射!