如何确定 LINQ 查询是 LINQ to SQL 还是 LINQ to Objects?
How can I determine if a LINQ query is going to be LINQ to SQL vs. LINQ to Objects?
通常 LINQ to SQL 和 LINQ to Objects 之间的区别不是问题(我认为从一开始就将其作为一个问题是过早的优化),但我如何确定哪个是发生了什么?
编写代码时知道这一点会很有用,但我担心有时只能在 运行 时间才能确定。
不是微优化来区分 Linq-To-Sql 和 Linq-To-Objects。后者要求在开始过滤之前将所有数据加载到内存中。当然,这可能是个大问题。
大多数 LINQ 方法都使用延迟执行,这意味着它只是构建 查询 但尚未执行(如 Select
或 Where
) .很少有人执行查询并将结果具体化到内存中的集合中(如 ToLIst
或 ToArray
)。如果你使用 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>
的东西,您不能确定它实际上是一个查询还是已经是一个内存中的对象。由于 AsQueryable
-method,即使是 IQueryable<T>
的 try-cast 也不会告诉你它到底是什么。也许您可以尝试将其转换为集合类型。如果转换成功,您可以确定它已经具体化,否则它不会告诉您它使用的是 Linq-To-Sql
还是 Linq-To-Objects
:
bool isMaterialized = queryLondonCustomers as ICollection<Customer> != null;
相关:EF ICollection Vs List Vs IEnumerable Vs IQueryable
我想到的第一个解决方案是检查查询提供程序。
如果查询已具体化,这意味着数据已加载到内存中,则使用 EnumerableQuery(T)。否则,将使用特殊的查询提供程序,例如,System.Data.Entity.Internal.Linq.DbQueryProvider
for entityframework.
var materialized = query
.AsQueryable()
.Provider
.GetType()
.GetGenericTypeDefinition() == typeof(EnumerableQuery<>);
然而,以上是理想情况,因为有人可以实现自定义查询提供程序,其行为类似于 EnumerableQuery
。
出于不同的原因,我有同样的问题。
纯粹根据您的标题和初始描述来判断(这就是 google 搜索将我带到这里的原因)。
预编译,给定一个实现了 IQueryable 的实例,没有办法知道接口背后的实现。
在运行时,您需要像@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;
}
}
在我们的例子中,我们正在动态添加额外的过滤器,但是 运行 处理不同提供商的 case-sensitivity/nullreference 处理的不同问题。
因此,在运行时我们不得不根据提供者的类型调整我们添加的过滤器,并最终添加了这个扩展方法:
通常 LINQ to SQL 和 LINQ to Objects 之间的区别不是问题(我认为从一开始就将其作为一个问题是过早的优化),但我如何确定哪个是发生了什么?
编写代码时知道这一点会很有用,但我担心有时只能在 运行 时间才能确定。
不是微优化来区分 Linq-To-Sql 和 Linq-To-Objects。后者要求在开始过滤之前将所有数据加载到内存中。当然,这可能是个大问题。
大多数 LINQ 方法都使用延迟执行,这意味着它只是构建 查询 但尚未执行(如 Select
或 Where
) .很少有人执行查询并将结果具体化到内存中的集合中(如 ToLIst
或 ToArray
)。如果你使用 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>
的东西,您不能确定它实际上是一个查询还是已经是一个内存中的对象。由于 AsQueryable
-method,即使是 IQueryable<T>
的 try-cast 也不会告诉你它到底是什么。也许您可以尝试将其转换为集合类型。如果转换成功,您可以确定它已经具体化,否则它不会告诉您它使用的是 Linq-To-Sql
还是 Linq-To-Objects
:
bool isMaterialized = queryLondonCustomers as ICollection<Customer> != null;
相关:EF ICollection Vs List Vs IEnumerable Vs IQueryable
我想到的第一个解决方案是检查查询提供程序。
如果查询已具体化,这意味着数据已加载到内存中,则使用 EnumerableQuery(T)。否则,将使用特殊的查询提供程序,例如,System.Data.Entity.Internal.Linq.DbQueryProvider
for entityframework.
var materialized = query
.AsQueryable()
.Provider
.GetType()
.GetGenericTypeDefinition() == typeof(EnumerableQuery<>);
然而,以上是理想情况,因为有人可以实现自定义查询提供程序,其行为类似于 EnumerableQuery
。
出于不同的原因,我有同样的问题。
纯粹根据您的标题和初始描述来判断(这就是 google 搜索将我带到这里的原因)。
预编译,给定一个实现了 IQueryable 的实例,没有办法知道接口背后的实现。
在运行时,您需要像@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;
}
}
在我们的例子中,我们正在动态添加额外的过滤器,但是 运行 处理不同提供商的 case-sensitivity/nullreference 处理的不同问题。 因此,在运行时我们不得不根据提供者的类型调整我们添加的过滤器,并最终添加了这个扩展方法: