entity framework返回错误数据
我有一个Entity Framework 6.1项目,它正在查询SQL Server 2012数据库表并返回不正确的结果。
为了说明发生了什么,我创建了两个应该具有完全相同结果的查询。 表ProjectTable
有23列和20500行:
var test1 = db.ProjectTable .GroupBy(t => t.ProjectOwner) .Select(g => g.Key) .ToArray(); var test2 = db.ProjectTable .ToArray() .GroupBy(t => t.ProjectOwner) .Select(g => g.Key) .ToArray();
查询旨在获取表中所有不同项目所有者的列表。 第一个查询在SQL Server上执行繁重的工作,第二个查询将整个表下载到内存中,然后在客户端处理它。
第一个变量test1
的长度约为300个。 第二个变量test2
的长度为5。
以下是EF生成的原始SQL查询:
-- test1 SELECT [Distinct1].[ProjectOwner] AS [ProjectOwner] FROM ( SELECT DISTINCT [Extent1].[ProjectOwner] AS [ProjectOwner] FROM [dbo].[ProjectTable] as [Extent1] ) AS [Distinct1] -- test2 SELECT Col1, Col2 ... ProjectOwner, ... Col23 FROM [dbo].[ProjectTable]
当我运行此查询并分析返回的实体时,我注意到返回了完整的20500行,但ProjectOwner
列被仅有5个不同用户中的一个覆盖!
var test = db.ProjectTable.ToArray();
我想也许是SQL Server,所以我做了一个数据包跟踪并在TDS上过滤。 随机查看原始流我看到许多名称不在5的列表中,所以我知道数据正在通过线路正确发送。
如何查看EF获取的原始数据? 有什么东西可能会搞乱缓存并拉出不正确的结果吗?
如果我在SSMS或Visual Studio中运行查询,则返回的列表是正确的。 只有EF有这个问题。
编辑
好的,我添加了另一项测试,以确保我的理智得到控制。 我接受了test2
原始sql查询并执行了以下操作:
var test3 = db.Database .SqlQuery(@"SELECT Col1..Col23") .ToArray() .Select(t => t.ProjectOwner) .Distict() .ToArray();
我得到了正确的300个名字!
简而言之:
- EF向SQL Server发送预计的DISTINCT查询会返回正确的结果
- 让EF选择整个表,然后使用LINQ进行投影和DISTINCT,数据返回不正确的结果
- 赋予EF 完全相同的查询! 子弹#2生成并执行原始SQL查询,返回正确的结果
下载entity framework源并单步执行许多Enumerator
,我发现了这个问题。
在Shaper.HandleEntityAppendOnly
方法( 在此处找到 )中,在第187行调用Context.ObjectStateManager.FindEntityEntry
方法。 令我惊讶的是,返回了一个非null值! 等一下,不应该有任何缓存结果,因为我要返回所有行?!
那是我发现我的桌子没有主键的时候!
在我的辩护中,该表实际上是一个我正在使用的视图的缓存,我只是做了一个 SELECT * INTO CACHETABLE FROM USERVIEW
然后,我查看entity framework认为哪个列是我的主键(他们称之为单键),它恰好是他们选择的列只有… 鼓请 … 5个独特的值!
当我看到EF生成的模型时,果然! 该列被指定为主键。 我将密钥更改为相应的列,现在一切正常!