[英]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;
我想到的第一個解決方案是檢查查詢提供程序。
如果查詢是物化的,這意味着數據被加載到內存中,則使用EnumerableQuery(T) 。 否則,將使用特殊的查詢提供程序,例如,用於實體框架的System.Data.Entity.Internal.Linq.DbQueryProvider
。
var materialized = query
.AsQueryable()
.Provider
.GetType()
.GetGenericTypeDefinition() == typeof(EnumerableQuery<>);
但是,上述情況是理想的情況,因為有人可以實現自定義查詢提供程序,其行為類似於EnumerableQuery
。
我有同樣的問題,出於不同的原因。
純粹根據你的標題和初始描述來判斷(這就是谷歌搜索把我帶到這里的原因)。
預編譯,給定一個實現了 IQueryable 的實例,沒有辦法知道接口背后的實現。
在運行時,您需要像@Danny Chen 提到的那樣檢查實例的 Provider 屬性。
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;
}
}
在我們的例子中,我們動態地添加了額外的過濾器,但是在不同的提供者上遇到了不同的大小寫敏感/空引用處理的問題。 因此,在運行時,我們必須根據提供者的類型調整我們添加的過濾器,並最終添加了這個擴展方法:
在net core 6中使用EF 核心
要查看提供程序是否為 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(...)
這樣只能在數據庫中執行的方法,並且您希望在客戶端執行的情況下分支到其他東西,這將非常有用。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.