我正在开发一个asp.net mvc-5 Web应用程序。我有以下2个模型类: -
public class ScanInfo
{
public TSServer TSServer { set; get; }
public Resource Resource { set; get; }
public List<ScanInfoVM> VMList { set; get; }
}
public class ScanInfoVM
{
public TSVirtualMachine TSVM { set; get; }
public Resource Resource { set; get; }
}
现在这两个操作将是相同的: -
Operation1
var vmlist = scaninfo.SelectMany(a => a.VMList).ToList();
if (vmlist.Any(a2 => a2.Resource.RESOURCENAME.ToLower() == vmname.ToLower()))
操作2
if (scaninfo.Any(a=>a.VMList.Any(a2 => a2.Resource.RESOURCENAME.ToLower() == vmname.ToLower())))
或者他们会以不同的方式执行?
由于
答案 0 :(得分:3)
第一个选项有一个昂贵的操作,即使用SelectMany
展平列表元素。
除此之外,两者都应该相同,即。在找到第一场比赛时休息。
如果是数据库
如果在数据库上执行此查询,则第一个选项是错误的,因为它会将所有数据带到应用程序内存(因为您使用的是ToList
)和稍后它将在内存对象中执行Any
检查。
第二个将在数据库端执行查询,并仅将结果返回给应用程序。它不会将数据带回应用程序。
答案 1 :(得分:2)
不,他们将以不同的方式执行。
第一个更糟糕。它会导致scaninfo被枚举,然后将所有ScanInfoVM放入一个列表中,然后使用Any
过滤ScanInfoVM。
第二个要好得多,但它正在检查是否存在任何具有符合您标准的ScanInfoVM的ScanInfo
。
简而言之,它们以不同的方式执行并检查稍微不同的东西,但由于您只关心是否存在,那么它们应该给出相同的结果,但第二个将更快地执行,从数据库返回仅一个布尔值并且它会在找到第一个之后停止查找,而第一个从数据库返回所有内容然后开始检查。
如果您只是在第一个操作中删除ToList()
,那么执行更好的操作就需要运行探查器来确定。我怀疑它们会以相同的方式执行,但这取决于数据库提供程序如何将表达式树转换为SQL以及SQL服务器如何优化结果查询。
答案 2 :(得分:2)
var vmlist = scaninfo.SelectMany(a => a.VMList).ToList();
这将运行SQL查询以获取与VMList
行关联的每个ScanInfo
行,为每个行构建一个VMList
对象,然后在内存中创建一个列表以将它们全部存储
if (vmlist.Any(a2 => a2.Resource.RESOURCENAME.ToLower() == vmname.ToLower()))
这将贯穿该列表,并且如果Resource.RESOURCENAME.ToLower() == vmname.ToLower()
为真(不记得vmname.ToLower()
的值),则每个项目计算出来并在找到匹配时立即返回true,否则返回false它永远找不到一个。
if (scaninfo.Any(a=>a.VMList.Any(a2 => a2.Resource.RESOURCENAME.ToLower() == vmname.ToLower())))
这将在数据库上运行EXISTS
SQL查询,并相应地返回true
或false
。
我们通常希望这会更快,当然也可以使用更少的内存。
答案 3 :(得分:1)
查看Enumerable.cs的源代码,Any定义为:
public static bool Any<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) {
if (source == null) throw Error.ArgumentNull("source");
if (predicate == null) throw Error.ArgumentNull("predicate");
foreach (TSource element in source) {
if (predicate(element)) return true;
}
return false;
}
和Select以及对SelectIterator的调用是:
public static IEnumerable<TResult> Select<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, int, TResult> selector) {
if (source == null) throw Error.ArgumentNull("source");
if (selector == null) throw Error.ArgumentNull("selector");
return SelectIterator<TSource, TResult>(source, selector);
}
static IEnumerable<TResult> SelectIterator<TSource, TResult>(IEnumerable<TSource> source, Func<TSource, int, TResult> selector) {
int index = -1;
foreach (TSource element in source) {
checked { index++; }
yield return selector(element, index);
}
}
所以它们的执行方式会有所不同,但是从查看你的LINQ表达式开始,它们将评估。
HTH