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

时间:2014-06-27 14:14:39

标签: c# linq entity-framework sql-server-2008-r2 linq-to-entities

与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,SQL Server生成了一个糟糕的计划,而且,由于我无法添加索引/连接提示,因此我创建了一个存储过程,该程序包含了上述Linq表达式生成的SQL。

我知道我应该能够通过Entity Framework访问存储过程,但是我使用的是之前使用非常轻量级的代码优先实现的项目(例如,没有.edmx文件)和我对整个EF事物都不熟悉,并且不知道如何将新程序绑定到EF。我知道可以做到,但我试图直接调用该程序。

我解决了这个问题:

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

这似乎有效,除了一个问题。当遍历linq可查询时,一切都在游泳。但是,当我使用存储过程时,我得到重复的记录。

例如,如果我有一个包含3个yyy记录的xxx记录,我会从linq表达式中获取单个xxx记录,并且正如预期的那样,它包含内部集合中的3个yyy记录。

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

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

为什么?有什么想法吗?

(同样,对EF来说是新手,所以请原谅术语中的错误。)

1 个答案:

答案 0 :(得分:0)

我相信EF会根据您定义的主键将结果视为重复。在EF5中,这将使用&#34;实体密钥&#34;来定义。唯一定义实体的字段上的属性(多部分主键将在多个字段上设置此项)。

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

你的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