[英]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.