IQueryable的簡單封裝

崩壞的領航員發表於2020-12-27

IQueryable的簡單封裝

前言

前兩天在園子上看到一個問題

半年前我也考慮過這些問題,但由於這樣那樣的問題,沒有嘗試去解決.

後來公司用上了 abp vnext ,然後有一部分程式碼可以這樣寫

protected override IQueryable<Resource> CreateFilteredQuery(GetResourceDto input)
{
    return ReadOnlyRepository.WhereIf(
        input.ParentId.HasValue,
        item => item.ParentId == input.ParentId
    ).WhereIf(
        input.Id.HasValue,
        item => item.Id == input.Id
    );
}

用的時候感覺還是有點方便的,但沒怎麼考慮過如何實現,也就這樣一直用著了.

看到上面那個問題之後就想起來了這茬兒.

第一階段

眾所周知,去掉 if 的最簡單的方式就是用三元 ()?():()

param = string.IsNullOrEmpty(x.CustomerID)
        ?param
        :param.And(x => x.CustomerID == query.CustomerID);

講道理,去掉了 if ,但是並沒有感覺比用 if 的時候好多少

第二階段

眾所周知,覺得程式碼不好看(冗餘多)的時候,你應該做點封裝了

一般 來說,查詢時用的應該是 IQueryable<T> Where(......)

所以可以對 IQueryable<T> 封裝一些 簡單 的擴充套件方法

public static class QueryClass
{
    public static IQueryable<T> WhereIf<T>(this IQueryable<T> query, bool flag, Expression<Func<T, bool>> expression)
    {
        return flag ? query.Where(expression) : query;
    }

    public static IQueryable<T> WhereIf<T>(this IQueryable<T> query, string flag, Expression<Func<T, bool>> expression)
    {
        return string.IsNullOrEmpty(flag) ? query : query.Where(expression);
    }
}

用的時候就比較簡單了

先定義一下(資料庫)實體

public class Entity
{
    // 可為空
    public Guid? Id { get; set; }
    // 字串
    public string Name { get; set; }
    // 值型別
    public int Num { get; set; }
}

以上應該是程式裡面用到的最多的3種資料型別了(大概)

然後整點資料

List<Entity> list = new()
{
    new Entity { Id = Guid.NewGuid(), Name = "2" },
    new Entity { Id = Guid.NewGuid(), Name = "233333" },
    new Entity { Id = Guid.NewGuid(), Name = "233333", Num = 233333 },
    new Entity { Id = Guid.NewGuid(), Name = "233333", Num = 3 },
    new Entity { Id = Guid.NewGuid(), Name = "23" },
    ......
    ......
    new Entity { Id = Guid.NewGuid(), Name = "23", Num = 2333 },
};

然後前端傳了點資料過來

Entity input = new()
{
    Id = null,
    Name = "233",
    Num = 233
};

寫條件的時候大概就像下面這樣

var result = list.AsQueryable()
.WhereIf(input.Id.HasValue, item => item.Id == input.Id)
.WhereIf(input.Name, item => item.Name.Contains(input.Name))
.WhereIf(input.Num > 0, item => item.Num > input.Num * 20).ToList();

感覺用的時候還是挺方便簡潔的

再多做點(過度)封裝應該會更好用

第三階段

抱歉我還在第二層......

相關文章