[英]Strongly typed Linq filtering method
我有點厭倦了編寫這樣的服務層代碼:
下面的代碼只是讀者的一個例子。 所以他們可能有錯誤或錯別字,抱歉:)
//ViewModel
public class EntityIndexFilterPartial
{
public int? Id { get; set; }
public DateTime? StartDate { get; set; }
public DateTime? EndDate { get; set; }
public IEnumerable<SelectListItem> StatusList { get; set; }
public int? StatusID { get; set; }
}
//Service Layer method
//Method parameters are reperesents view model properties
public IQueryable<Entity> FilterBy(int? id, DateTime? startDate, DateTime? endDate, int? statusId)
{
var filter = _db.Entities.AsQueryable();
if (id.HasValue)
filter = filter.Where(x => x.Id == id.Value);
if (startDate.HasValue)
filter = filter.Where(x => x.StartDate >= startDate.Value);
if (endDate.HasValue)
filter = filter.Where(x => x.EndDate <= endDate.Value);
if (statusId.HasValue)
filter = filter.Where(x => x.EntityStatus.StatusID == statusId);
return filter;
}
我搜索了一些智能設計的代碼。 我知道Dynamic LINQ庫 ,我也使用它。 但我正在尋找強類型過濾 。 我不想寫魔術字符串或某些字符串。
所以基本上我找到了一些解決方案,但我希望從這個社區中聽到一些寫得很好的智能代碼。 當然可能有很多解決方案,但是你又如何編寫強類型過濾服務層代碼。 有任何想法嗎...
以下是我的一些解決方案:
解決方案1:相同的FilterBy方法但參數不同,現在采用表達式列表。 所以這意味着我在控制器中創建謂詞列表並將其發送到此處。
public IQueryable<Entity> FilterBy(List<Expression<Func<Entity,bool>>> predicateList)
{
var filter = _db.Entities.AsQueryable();
foreach (var item in predicateList)
{
filter = filter.FilterBy(item);
}
return filter;
}
解決方案2: FilterBy方法將EntityIndexFilterPartial作為Application Service層(而非域服務)中的參數。 我確信這個設計有一些問題,但我想聽聽你的意見。
public IQueryable<Entity> FilterBy(EntityIndexFilterPartial filterPartial)
{
//I'm calling the domain service layer FilterBy method such as like in solution 1.
}
解決方案3:我認為這個比其他人好得多,但我仍在考慮更簡單和更好的代碼。
//helper class
public static class FilterByHelper
{
public static IQueryable<T> If<T>(this IQueryable<T> filter, bool condition, Expression<Func<T, bool>> predicate)
{
if (condition)
return filter.FilterBy(predicate);
return filter;
}
public static IQueryable<T> FilterBy<T>(this IQueryable<T> filter, Expression<Func<T, bool>> predicate)
{
return filter.Where(predicate);
}
}
public IQueryable<Entity> FilterBy(int? id, DateTime? startDate, DateTime? endDate, int? statusId)
{
return _db.Entities
.If(id.HasValue, x => x.Id == id.Value)
.If(startDate.HasValue, x => x.StartDate >= startDate.Value)
.If(endDate.HasValue, x => x.EndDate <= endDate.Value)
.If(statusId.HasValue, x => x.EntityStatus.StatusID == statusId);
}
我知道這成了一個長長的問題,但我希望我清楚地問我想問什么。
作為一個快速而簡單的問題,您是否知道任何設計巧妙的代碼,以避免我們編寫這些過濾代碼的相同行?
順便說一句,我不是在尋找設計模式解決方案或大答案,你可以給我一些例子或者說如何找到更好的路徑就足夠了。
當然,如果你寫一個完整的解釋回復,我會被批評。
謝謝。
你試過簡單的||
條件?
return _db.Entities
.Where(x => id == null || x.Id == id.Value)
.Where(x => startDate == null || x.StartDate >= startDate.Value)
.Where(x => endDate == null || x.EndDate <= endDate.Value)
.Where(x => statusId == null || x => x.EntityStatus.StatusID == statusId);
? 我希望在查詢優化之后,無操作過濾器相當於根本不添加過濾器。
我通過使用流暢的擴展方法解決了這個問題。 我覺得這是解決這類特殊問題的一個非常好的解決方案。 使用流暢的定義過濾器樣式的好處是,當您實際使用它時,它會產生一些真正可讀的代碼。 這在實踐中的作用是它使您的服務層更具動態性。
例如
如果你有
public class User {
public int Id {get;set;}
public DateTime CreatedOn {get;set;}
public string Name {get;set;}
public DateTime BirthDate {get;set;}
}
你可以編寫一些與此類似的過濾器
public IQueryable<User> OlderThan(this IQueryable<User> users, DateTime olderThan){/*implementation*/}
public IQueryable<User> CreatedAfter(this IQueryable<User> users, DateTime createdAfter){/*implementation*/}
//or something more generic
public IQueryable<User> WhereName(this IQueryable<User> users, Expression<Func<string,bool>> nameQuery){/*implementation*/}
然后鏈接這些東西就像這樣:
users
.CreatedAfter(new DateTime(2011,1,1))
.OlderThan(new DateTime(1985,1,2))
.WhereName(n=>n.StartsWith("L"));
這樣可以使您的過濾邏輯更加動態,而無需創建難以維護且復雜的捕獲式過濾器
在實踐中這意味着
在我的博客中,我用一些真實的例子來討論這個方法。 http://blog.staticvoid.co.nz/2013/2/25/a_case_for_generic_repositories
您好Yusuf這篇文章可能對您有幫助。解決方案看起來很聰明,它實現了linq查詢條件的動態,看起來很簡單。
http://amitech.co/amitech-lab/item/dynamically-add-conditions-in-linq
希望能幫助到你
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.