簡體   English   中英

如何確定 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 方法都使用延遲執行,這意味着它只是構建查詢但尚未執行(如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>的東西,你不能確定它實際上是一個查詢還是已經是一個內存對象。 由於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

我想到的第一個解決方案是檢查查詢提供程序

如果查詢是物化的,這意味着數據被加載到內存中,則使用E​​numerableQuery(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.EnumerableQueryEnumerableQuery<T>的基本類型 - 因此您不必測試泛型)測試提供者,可以得到相反的結果。

如果您有像EF.Functions.Like(...)這樣只能在數據庫中執行的方法,並且您希望在客戶端執行的情況下分支到其他東西,這將非常有用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM