2016-01-20 69 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