簡體   English   中英

傳遞GetWhere查詢(功能 <entityDTO,bool> )到需要(Func <entity,bool> )參數起作用

[英]Passing a GetWhere query (Func<entityDTO,bool>) to a data layer method which needs a (Func<entity,bool>) parameter to work

我在使用實體框架的數據訪問類中具有以下方法:

public static IEnumerable<entityType> GetWhere(Func<entityType, bool> wherePredicate)
{
    using (DataEntities db = new DataEntities())
    {
        var query = (wherePredicate != null)
            ? db.Set<entityType>().Where(wherePredicate).ToList()
            : db.Set<entityType>().ToList();                    
        return query;
    }
}

當我在所有層上使用實體時,此方法工作正常……但是,我試圖轉向使用DTO類,並且我想做以下事情:

public static IEnumerable<EntityTypeDTO> GetWhere(Func<EntityTypeDTO, bool> wherePredicate)
{
    //call a method here which will convert Func<EntityTypeDTO,bool> to 
    // Func<EntityType,bool>

    using (DataEntities db = new DataEntities())
    {
        var query = new List<EntityType>();
        if (wherePredicate == null)
        {
            query = db.Set<EntityType>().ToList();
        }
        else
        {   
            query = (wherePredicate != null)
                ? db.Set<EntityType>().Where(wherePredicate).AsQueryable<EntityType>().ToList()
                : db.Set<EntityType>().ToList();
        }
        List<EntityTypeDTO> result = new List<EntityTypeDTO>();
        foreach(EntityType item in query)
        {
            result.Add(item.ToDTO());
        }

        return result;
    }
}

本質上,我想要將Func轉換為Func的方法。

我想我必須將Func分解為一個表達式樹,然后以某種方式在entityType中對其進行重建?

我想這樣做是為了允許表示層只通過表達式查詢?

我是否缺少基本的知識,還是有一種更簡單的設計模式可以將查詢從DTO傳遞到數據訪問類,而又不知道查詢的詳細信息?

我試圖使DTO從似乎也不起作用的實體繼承?

如果有一個更好的設計模式,我想念一個指針,那么我可以從那里進行調查...

首先,我建議您將自己的查詢層放在Entity Framework的前面,而不要允許傳入任何任意Func,因為將來通過很容易通過Entity Framework無法轉換為SQL的Func語句(它只能翻譯一些表達式-基本情況很好,但是例如,如果您的表達式調用C#方法,則Entity Framework可能會失敗)。

因此,您的搜索層可能具有您作為條件構建的類(例如,“ ContainsName”搜索類或“ ProductHasId”類),然后將其轉換為搜索層中的表達式。 這將您的應用程序與ORM完全分開,這意味着ORM詳細信息(例如實體或類似Funcs可以翻譯和不能翻譯的限制)不會泄漏出去。 關於這種安排,有很多關於這種安排的文章。

最后要說明的,不過,如果你正在接近ORM層,實體框架是非常聰明的,你可能會得到一個很長的路要走,但不嘗試翻譯你的Func鍵<DTO,布爾>到Func鍵<實體,布爾>。 例如,在下面的代碼中,訪問“ context.Products”將返回一個“ DbSet”,並在其上調用Select會返回一個IQueryable,而在Where上調用還會返回一個IQueryable。 Entity Framework會將所有內容轉換為一個SQL語句,因此不會將所有其他產品拉入內存,然后過濾該內存集上的ID,即使過濾器在計划中運行,它實際上也會在SQL中執行過濾類型(相當於您的情況下的DTO)而不是Entity Framework實體-

var results = context.Products
    .Select(p => new { ID = p.ProductID, Name = p.ProductName })
    .Where(p => p.ID < 10)
    .ToList();

執行的SQL是:

SELECT 
    [Extent1].[ProductID] AS [ProductID], 
    [Extent1].[ProductName] AS [ProductName]
FROM [dbo].[Products] AS [Extent1]
WHERE [Extent1].[ProductID] < 10

因此,如果您更改代碼以得到類似的信息。

return context.Products
    .Map<Product, ProductDTO()>()
    .Where(productDtoWherePredicate)
    .ToList();

..那么您可能已經擁有的Funcs就好了。 我假定您已經具有從EF實體到DTO的某種映射功能(但如果沒有,則可能需要研究AutoMapper來幫助您-它支持“投影”,基本上是IQueryable映射)。

我要回答這個問題。感謝Dan的快速解答。 看您在說什么,我可以編寫一組查詢/過濾器。 例如,采用以下代碼:

GetProducts().GetProductsInCategory().GetProductsWithinPriceRange(minPrice, maxPrice);

該代碼將按以下方式運行:獲取產品將獲取表中的所有產品,其余功能將過濾結果。 如果所有查詢都這樣運行,可能會給數據訪問層/ DB服務器連接帶來很大的負擔...不確定。

要么

我還將研究的另一種方法是:如果每個函數創建一個Linq表達式,則可以將它們組合如下: 如何將多個linq查詢組合到一個結果集中? 這可以讓我以可以從數據庫返回過濾后的結果集的方式執行此操作。

無論哪種方式,我都將其標記為已回答。 我將在有更多詳細信息時進行更新。

暫無
暫無

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

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