簡體   English   中英

強類型Linq過濾方法

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

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