对具有原始存储过程的实体的Linq返回数据的副本

本文关键字:Linq 返回 数据 副本 实体 原始 存储过程 | 更新日期: 2023-09-27 18:10:28

SQL Server 2008R2接口:

我有一个linq表达式:
IQueryable<xxx> xxxResult =
     (from t in _context.xxxx.AsNoTracking().Include("yyy")
     where t.zzz >= lowNumber
           && t.zzz <= highNumber
           && t.qqq == someValue
     select t);            

(它可能在确切的查询中不重要,但它在那里以防它。)

Linq生成的SQL Server生成了一个糟糕的计划,并且,由于我不能添加索引/连接提示,我创建了一个存储过程来包装上述Linq表达式生成的SQL。

我知道我应该能够通过实体框架访问存储过程,但我使用的是以前的项目,该项目使用了非常轻的代码优先实现(例如,没有.edmx文件),我对整个EF有点陌生,不知道如何将新过程绑定到EF中。我知道这是可以做到的,但我正试图直接调用这个过程。

I worked this out:

IQueryable<xxx> xxxResult = 
    _context.xxxx.SqlQuery("GetData @p0, @p1, @p2",  someValue, lowNumber, highNumber)
                 .AsNoTracking().AsQueryable();

这似乎工作,除了一个问题。当迭代linq queryable时,一切都很顺利。但是,当我使用存储过程时,我得到了重复的记录。

例如,如果我有一条xxx记录,在一个集合中包含3条yyy记录,我从linq表达式中得到一条xxx记录,并且它如预期的那样,在内部集合中包含3条yyy记录。

存储过程,对于相同的数据集,在可查询对象上迭代返回三个xxx记录,每个xxx记录包含相同的3个yyy记录。

同样,存储过程执行与linq表达式生成的完全相同的SQL。

为什么?什么好主意吗?

对具有原始存储过程的实体的Linq返回数据的副本

我相信EF将您的结果视为基于您定义的主键的副本。在EF5中,这将在唯一定义实体的字段上使用"Entity Key"属性来定义(多部分主键将在多个字段上设置此属性)。

如果您的过程返回的记录与它已经返回的记录匹配(仅基于主键字段),那么它将返回对前一个记录的引用。

你的LINQ表达式使用. asnotracking,这应该可以防止这种缓存行为。

我猜使用存储过程的。asnotracking()在它被缓存后发生,并且没有您正在寻找的效果。

请确保在模型上正确设置了主键。

下面是一篇描述视图行为的文章:http://jepsonsblog.blogspot.in/2011/11/enitity-framework-duplicate-rows-in.html应该与您在存储过程中看到的内容相似。

看起来像在Code First中,您将使用[Key]注释来指定您的唯一密钥:http://msdn.microsoft.com/en-us/data/jj591583.aspx