Linq to Sql 或linq to entities 與SQL查詢結果不一致 返回重復結果問題


用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 = db.entity.select(v=>v);//entity為實體對象

得出的結果為:

====LINQ返回錯誤的結果=====

列1(key列) 列2 列3

1             a1    a1         

1             a1    a1  (這行是錯誤的)

3             a3    a3

問題分析:

我們會發現,第2條記錄與第一條記錄是一樣的,原因就在於實體對象中的Key列即列1的值相同(在我們的例子中都為1),

那么LINQ返回第一條數據時,沒有問題,正常返回;

返回第二條時,判斷Key列的值,發現都為1,那么就認為第二條數和第一條數據是一樣的,所以直接返回第一行記錄的值,做為第二條記錄。

第三條記錄,key列不同,取回正確數據。

如果LINQ的查詢還附加排序也會影響LINQ查詢的結果,總之會返回不同的錯誤結果 

 

解決方法:

1.找出視圖中可以用來唯一標識該行記錄的那些列,在edmx中將它們設為實體鍵(Key列),在我的項目中還給這個字段加了唯一鍵約束,防止LINQ查詢結果出錯。

通過上面分析,我們就可以明白為什么出現這種問題都是在使用視圖的時候,因為如果是表的話,那么基本上主鍵會被判斷為實體對象的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了。

2.使用EF執行SQL語句的方法 DbContext.Database.SqlQuery<T>(視圖名),也可以解決問題,效率就不用我說,通過SQL Server Profiler跟蹤測試一下就知道了。

本文參考了TobeorNot的經驗加補充,如有更好的方法,請指教。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM