通常情况下,LINQ to SQL和LINQ to Objects之间的区别并不是什么大问题,但是如何确定正在发生哪种情况呢?
在编写代码时了解这一点会很有用,但有时只能在运行时确保。
在编写代码时了解这一点会很有用,但有时只能在运行时确保。
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;
!String.IsNullOrWhiteSpace(cust.City)
)。IEnumerable<T>
,你不能确定它实际上是一个查询还是已经是内存中的一个对象。即使尝试将其转换为 IQueryable<T>
,也不能确定它实际上是什么,因为有 AsQueryable
-method 存在。也许你可以尝试将其转换为集合类型。如果转换成功,你可以确定它已经被实现了,但否则它并不告诉你它是使用的 Linq-To-Sql
还是 Linq-To-Objects
。bool isMaterialized = queryLondonCustomers as ICollection<Customer> != null;
相关内容: EF ICollection Vs List Vs IEnumerable Vs IQueryable
AsEnumerable()
不会立即执行查询。延迟执行仍然保留,因此您可以进一步添加 Select()
、Where()
,但它们最终将被 Linq to Objects 拦截。 - haim770AsEnumerable()
不会实现查询(请参见http://referencesource.microsoft.com/#System.Core/System/Linq/Enumerable.cs,825)。 - haim770我首先想到的解决方案是检查查询提供程序。
如果查询已经被实例化,也就是数据已经加载到内存中,那么会使用EnumerableQuery(T)。否则,会使用一个特殊的查询提供程序,例如对于entityframework,会使用System.Data.Entity.Internal.Linq.DbQueryProvider
。
var materialized = query
.AsQueryable()
.Provider
.GetType()
.GetGenericTypeDefinition() == typeof(EnumerableQuery<>);
EnumerableQuery
一样运行。在net core 6中使用EF core
要查看提供程序是否为EF提供程序,请使用以下代码:
if (queryable.Provider is Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider)
{
// Queryable is backed by EF and is not an in-memory/client-side queryable.
}
通过对提供程序进行 System.Linq.EnumerableQuery
的测试(EnumerableQuery<T>
的基本类型 - 因此您不必测试泛型),可以获得相反的结果。
如果您有像 EF.Functions.Like(...)
这样只能在数据库中执行的方法,并且您希望在客户端执行时分支到其他内容,则此功能非常有用。
出于不同的原因,我有相同的问题。
仅根据您的标题和初始描述(这就是为什么谷歌搜索将我带到这里的原因),可以判断在预编译时,鉴于实现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;
}
}
在我们的情况下,我们动态添加了额外的过滤器,但是在不同的提供程序上,大小写敏感性/空引用处理的处理方式不同,因此在运行时,我们必须根据提供程序的类型调整添加的过滤器,并最终添加了这个扩展方法:
IEnumerable<T>
,操作将使用 LINQ to Objects,但如果你有一个IQueryable<T>
,操作将使用“其他东西”。(当然,AsQueryable
会将IEnumerable<T>
包装成IQueryable<T>
,所以并不是100%......)你实际上在寻找什么样的东西? - Jon SkeetIQueryable
,请谨慎处理。您可以始终使用AsEnumerable()
选择内存中的处理方式,但必须注意其影响(将所有数据加载到内存中)。 - haim770