我有一个实体框架6.1项目,正在查询SQL Server 2012数据库表并获取不正确的结果。
为了说明正在发生的情况,我创建了2个查询,它们应具有完全相同的结果。该表ProjectTable
有23列和20500ish行:
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]
当我运行此查询并分析返回的实体时,我注意到返回了完整的20500ish行,但是该ProjectOwner
列被仅5个不同用户之一覆盖!
var test = db.ProjectTable.ToArray();
我以为可能是SQL Server,所以我进行了数据包跟踪并在TDS上进行了过滤。随机浏览原始流,我看到许多不在5列表中的名称,因此我知道数据正在正确地通过网络发送。
我如何查看EF获取的原始数据?是否有可能使高速缓存混乱并导致错误的结果?
如果我在SSMS或Visual Studio中运行查询,则返回的列表正确。只有EF出现此问题。
好的,我添加了另一个测试以确保我的理智得到控制。我进行了test2
原始sql查询,并执行了以下操作:
var test3 = db.Database
.SqlQuery<ProjectTable>(@"SELECT Col1..Col23")
.ToArray()
.Select(t => t.ProjectOwner)
.Distict()
.ToArray();
我得到正确的300个名字!
在下载了Entity Framework源代码并逐步完成许多步骤后Enumerator
,我发现了问题。
在该Shaper.HandleEntityAppendOnly
方法(在此处找到)中,在第187行Context.ObjectStateManager.FindEntityEntry
中调用了该方法。令我惊讶的是,返回了一个非空值!请稍等,因为我要返回所有行,所以不应有任何缓存的结果?
那是我发现我的表没有主键的时候!
为防御起见,该表实际上是我正在使用的视图的缓存,我只是做了一个 SELECT * INTO CACHETABLE FROM USERVIEW
然后,我查看了Entity Framework认为哪一列是我的主键(他们将其称为单例键),恰好碰巧他们选择的列只有...鼓声…… 5个唯一值!
当我查看EF生成的模型时,肯定可以!该列被指定为主键。我将密钥更改为适当的列,现在一切正常。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句