c# - 强类型 Linq 过滤方法

标签 c# linq strong-typing service-layer

我有点厌倦了编写这样的服务层代码行:

以下代码仅供读者引用。所以他们可能有错误或拼写错误,对此深表歉意:)

//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 library 并且我也在使用它。但我正在寻找强类型过滤。 我不想编写魔法字符串或类似的字符串。

所以基本上我找到了一些解决方案,但我想从这个社区听到一些编写良好的智能代码。当然可能有几十种解决方案,但您又将如何编写强类型过滤服务层代码。任何想法...

以下是我的一些解决方案:

解决方案 1: 相同的 FilterBy 方法但参数不同,现在采用表达式列表。所以这意味着我正在 Controller 中创建 predicateList 并将其发送到此处。

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 作为应用服务层(非领域服务)的参数。我确定这个设计存在一些问题,但我想听听您的意见。

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);

?我希望在查询优化之后,无操作过滤器相当于根本不添加过滤器。

关于c# - 强类型 Linq 过滤方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18026303/

相关文章:

c# - Visual Studio 后期生成事件命令行 "for"语法

c# - LINQ查询查找对象,其数据变量与输入变量最接近

c# - Expression.Call with Any 方法抛出异常

typescript - 如何在 Typescript 中扩展匿名类型

haskell - 如何在 haskell 类型规范中引用已经存在的类型变量?

javascript - 获取 $.post 返回 View

c# - 无法在运行 Mono 的 Mac OSX 上以 C# 加载 PNG

c# - 根据 Predicate<T> 清理 List<T> 的最可靠方法

.net - 如何在 linq to sql 中进行连接?

c - "Strong"通过单元素结构输入 C。编译器会做什么?