2016-01-20 66 views
1

我最初使用foreach循環,然後在循環中的每一個元素,我執行LINQ查詢,像這樣:對這種查詢類型使用LINQ的正確方法?

foreach (MyObject identifier in identifiers.Where(i => i.IsMarkedForDeletion == false)) 
{ 
    if (this.MyEntities.Identifiers.Where(pi => identifier.Field1 == pi.Field1 && identifier.Field2 == pi.Field2 && identifier.Field3 == pi.Field3).Any()) 
    { 
     return false; 
    } 
} 

return true; 

然後我修改了它,像這樣:

if (identifiers.Any(i => !i.IsMarkedForDeletion && this.MyEntities.Identifiers.Where(pi => i.Field1 == pi.Field1 && i.Field2 == pi.Field2 && i.Field3 == pi.Field3).Any())) 
{ 
    return false; 
} 

return true; 

我的問題是這仍然是使用LINQ的錯誤方式?基本上,我想消除對foreach循環的需要(似乎我應該能夠擺脫它),並通過不對列表中的每個元素執行單獨的數據庫查詢來更快地進行數據庫查詢。相反,我想爲所有元素執行一個查詢。謝謝!

+0

「標識符」,「MyEntities」和「MyEntities.Identifiers」的**類型**是什麼?他們在內存集合或數據庫實體? –

+0

只有MyEntities.Identifiers在數據庫中。其他一切都在記憶中。 – Andrew

+0

換句話說,'標識符'在內存集合中,'MyEntities.Identifiers'是'DbSet '。 –

回答

0

不幸的是修改版本將被精確地執行相同的方式(即多個數據庫查詢),如原foreach方法,因爲EF不支持數據庫查詢與連接到內存中的集合(除了原始的和枚舉類型的集合),所以如果你嘗試最合理的方式

bool result = this.MyEntities.Identifiers.Any(pi => identifiers.Any(i => 
    !i.IsMarkedForDeletion && 
    i.Field1 == pi.Field1 && i.Field2 == pi.Field2 && i.Field3 == pi.Field3)); 

你會得到

NotSupportedException異常:無法創建類型'YourType'的常量值。只有原始類型或枚舉類型在此上下文中受支持。

EF執行一個單一的數據庫查詢是從內存中集合手動建立與Concat每每個項目LINQ查詢,這樣

IQueryable<Identifier> query = null; 
foreach (var item in identifiers.Where(i => !i.IsMarkedForDeletion)) 
{ 
    var i = item; 
    var subquery = this.MyEntities.Identifiers.Where(pi => 
     pi.Field1 == i.Field1 && pi.Field2 == i.Field2 && pi.Field3 == i.Field3); 
    query = query != null ? query.Concat(subquery) : subquery; 
} 
bool result = query != null && query.Any(); 

查看如何Logging and Intercepting Database Operations到的唯一途徑監視EF的操作。

1

您可以用這種方式更改您的代碼,並按預期方式將其轉換爲SQL語句。 爲了防止轉換過程中出現運行時錯誤,最好將DBSet保存到IQueryable變量中; identifiers應該是IQueryable的,所以你應該改變你的代碼是這樣的(說實話,Resharper轉換您的foreach在這短短的labda):

IQueryable<MyObject2> identifiers = MyEntities.Identifiers.Where(i => i.IsMarkedForDeletion == false); 
IQueryable<MyObject2> ids = MyEntities.Identifiers.AsQueryable(); 
return identifiers.All(identifier => !ids.Any(pi => identifier.Field1 == pi.Field1 && identifier.Field2 == pi.Field2 && identifier.Field3 == pi.Field3)); 

如果identifiers是在內存中的集合,你可以在此更改代碼方式(希望字段string):

IQueryable<MyObject2> ids = MyEntities.Identifiers.AsQueryable(); 
string[] values = identifiers.Where(i => i.IsMarkedForDeletion == false).Select(i => String.Concat(i.Field1, i.Field2, i.Field3)).ToArray(); 
return !ids.Any(i => values.Contains(i.Field1 + i.Field2 + i.Field3)); 
+0

沒有。它不會**被轉換爲SQL,因此等同於原始的「foreach」方法 –

+0

您能否提供信息您爲什麼這麼認爲?因爲,我有實際的經驗,並且工作完美 – Michael

+0

因爲剛剛檢查過它 - EF6。 –

0

我會按如下方式使用它:

if (identifiers.Where(i => !i.IsMarkedForDeletion &&  
this.MyEntities.Identifiers.Field1 == i.Field1 && 
this.MyEntities.Identifiers.Field2 == i.Field2 && 
this.MyEntities.Identifiers.Field3 == i.Field3).Any())) 
{ 
    return false; 
} 

return true; 

我希望這可以幫助。儘管輸入更多,但使用多個'where'語句更容易理解和閱讀。

+0

我應該更具體。 MyEntities.Identifiers是一組數據庫,而不僅僅是一個對象。 – Andrew