最近用Entity Framework开发项目过程中,发现linq查询返回的结果,与SQL语句查询出的结果不一致。

问题表现为:SQL返回了我们期望的结果,但是LINQ查询出来的结果确是一些重复记录。

 

这种问题一般是对数据库视图进行查询时发生,问题产生的原因及现象如下:

1)使用.net 的linq to sql,或linq to entities 生成的实体对象,出于为提高效率等原因,会对每个对象自动判断出一些列做为实体对象的Key(EntityKey),

这个Key就是相当于我们表中的主键,查询结果时,会根据这个Key列的值进行判断,假设数据库中有视图View1有3条记录如下:

====View1=====

列1(key列) 列2 列3

1             a1    a1         

1             a2    a2  

3             a3    a3

 

2)假设此View1的实体对象中,列1判断为Key列(标识列),如果当前我们有一个如下的查询,SQL语句如下:

SELECT 列1,列2,列3 FROM [View1]

显然,查询出来正确的结果为:

====SQL返回正确的结果=====

列1(key列) 列2 列3

1             a1    a1         

1             a2    a2  

3             a3    a3

 

3)但是如果你用LINQ语句去查:var objs = objs.entities.select(v=>v);//entities为实体集对象

得出的结果为:

====LINQ返回错误的结果=====

列1(key列) 列2 列3

1             a1    a1         

1             a1    a1  (这行是错误的)

3             a3    a3

问题分析:

我们会发现,第2条记录与第一条记录是一样的,原因就在于实体对象中的Key列即列1的值相同(在我们的例子中都为1),

那么LINQ返回第一条数据时,没有问题,正常返回;

返回第二条时,判断Key列的值,发现都为1,那么就认为第二条数和第一条数据是一样的,所以直接返回第一行记录的值,做为第二条记录。

第三条记录,key列不同,取回正确数据。

 

解决方法:

找出视图中可以用来唯一标识该行记录的那些列,将它们设为实体键(Key列)。

通过上面分析,我们就可以明白为什么出现这种问题都是在使用视图的时候,因为如果是表的话,那么基本上主键会被判断为实体对象的Key,显示不会出现数据重复问题。

但是视图就不一样,特别是一些GroupBy语句创建的视图,.net底层自动判定的EntityKey,就会有问题,一般都是随便找一个或者几个列,GroupBy 语句的视图中,

基本上没有哪一个或者哪几个字段能做为记录唯一标识,那么我们只能给记录生成标识列来解决。

比如有一个视图View2的创建语句如下:

select col1,col2,col3,count(col4) as col4 from [table] group by col1,col2,col3

此时为了避免错误的结果,有些朋友,就把视图中col1,col2,col3的列都设为实体键,这样的确可以避免一些问题,有时候列太多了,全设为实体键,不是一个好办法。

但是,我们可以给记录自动生成列,就是使用 row_number() 方法,比如可以使用如下语句创建视图:

select  [index]=row_number() over (order by ID), col1,col2,col3,count(col4) as col4 from [table] group by col1,col2,col3

然后将index列设为实体键就OK了。