如何判断LINQ查询是LINQ to SQL还是LINQ to Objects?

时间:2016-09-05 08:40:32

标签: c# linq linq-to-sql

通常LINQ to SQL和LINQ to Objects之间的区别不是问题(我认为从一开始就让它成为一个问题是过早的优化),但我怎样才能确定发生了什么?

知道编写代码的时候会很有用,但我担心有时候只能在运行时确定代码。

3 个答案:

答案 0 :(得分:3)

微优化,以区分Linq-To-Sql和Linq-To-Objects。后者要求在开始过滤之前将所有数据加载到内存中。当然,这可能是一个重大问题。

大多数LINQ方法都使用延迟执行,这意味着它只是构建查询但它尚未执行(如SelectWhere)。很少有人正在执行查询并将结果具体化为内存中的集合(如ToLIstToArray)。如果您使用AsEnumerable,那么您也使用Linq-To-Objects,并且不会为其后的部分生成SQL,这意味着必须将数据加载到内存中(但仍然使用延迟执行)。

因此,请考虑以下两个查询。第一个选择并过滤数据库:

var queryLondonCustomers = from cust in db.customers
                           where cust.City == "London"
                           select cust;

而第二个选择全部并通过Linq-To-Objects进行过滤:

var queryLondonCustomers = from cust in db.customers.AsEnumerable()
                           where cust.City == "London"
                           select cust;

后者有一个优点:您可以使用任何.NET方法,因为它不需要转换为SQL(例如!String.IsNullOrWhiteSpace(cust.City))。

如果您只是获得IEnumerable<T>的内容,则无法确定它是实际上是查询还是已经是内存中对象。即使是IQueryable<T>的尝试,也不会告诉你因为AsQueryable-method而确实是什么。也许你可以尝试将它转换为集合类型。如果演员成功,你可以确定它已经实现了,但是它没有告诉你它是否正在使用Linq-To-SqlLinq-To-Objects

bool isMaterialized = queryLondonCustomers as ICollection<Customer> != null;

相关:EF ICollection Vs List Vs IEnumerable Vs IQueryable

答案 1 :(得分:1)

我想到的第一个解决方案是检查查询提供程序

如果查询具体化,这意味着数据已加载到内存中,则使用EnumerableQuery(T)。否则,将使用特殊查询提供程序,例如,System.Data.Entity.Internal.Linq.DbQueryProvider用于entityframework。

var materialized = query
                  .AsQueryable()
                  .Provider
                  .GetType()
                  .GetGenericTypeDefinition() == typeof(EnumerableQuery<>);

但是,上述情况是理想的情况,因为有人可以实现自定义查询提供程序,行为类似于EnumerableQuery

答案 2 :(得分:1)

出于不同的原因,我有同样的问题。

纯粹根据你的头衔评判&amp;初步说明(这就是谷歌搜索带我到这里的原因)。

预编译,给定一个实现IQueryable的实例,无法知道接口背后的实现。

在运行时,您需要检查实例的Provider属性,如@Danny Chen所提到的。

public enum LinqProvider
{
    Linq2SQL, Linq2Objects
}

public static class LinqProviderExtensions
{
    public static LinqProvider LinqProvider(this IQueryable query)
    {

        if (query.Provider.GetType().IsGenericType && query.Provider.GetType().GetGenericTypeDefinition() == typeof(EnumerableQuery<>))
            return LinqProvider.Linq2Objects;
        if (typeof(ICollection<>).MakeGenericType(query.ElementType).IsAssignableFrom(query.GetType()))
            return LinqProvider.Linq2Objects;

        return LinqProvider.Linq2SQL;
    }
}

在我们的示例中,我们正在动态添加其他过滤器,但遇到了对不同提供程序的区分大小写/无引用处理的不同处理问题。 因此,在运行时我们必须根据提供程序的类型调整我们添加的过滤器,最后添加此扩展方法: