使用内部.Any()与执行两次单独检查相同

时间:2015-10-23 16:18:15

标签: c# asp.net-mvc entity-framework linq entity-framework-6

我正在开发一个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())))

或者他们会以不同的方式执行?

由于

4 个答案:

答案 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查询,并相应地返回truefalse

我们通常希望这会更快,当然也可以使用更少的内存。

答案 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