通常LINQ to SQL和LINQ to Objects之间的区别不是问题(我认为从一开始就让它成为一个问题是过早的优化),但我怎样才能确定发生了什么?
知道编写代码的时候会很有用,但我担心有时候只能在运行时确定代码。
答案 0 :(得分:3)
不微优化,以区分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>
的内容,则无法确定它是实际上是查询还是已经是内存中对象。即使是IQueryable<T>
的尝试,也不会告诉你因为AsQueryable
-method而确实是什么。也许你可以尝试将它转换为集合类型。如果演员成功,你可以确定它已经实现了,但是它没有告诉你它是否正在使用Linq-To-Sql
或Linq-To-Objects
:
bool isMaterialized = queryLondonCustomers as ICollection<Customer> != null;
答案 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;
}
}
在我们的示例中,我们正在动态添加其他过滤器,但遇到了对不同提供程序的区分大小写/无引用处理的不同处理问题。 因此,在运行时我们必须根据提供程序的类型调整我们添加的过滤器,最后添加此扩展方法: