【问题标题】:Using filters in linq expression tree在 linq 表达式树中使用过滤器
【发布时间】:2021-04-22 19:40:17
【问题描述】:

我的想法是公开一个api 控制器​/api​/Events​/{clientId}​/{projectId}/{eventTypeId} 这些树形参数在查询我的db.Events 表时将起到过滤器的作用。 如果我通过ClientId,而不通过其他两个过滤器,它应该只通过ClientId 进行过滤。

我试过这个方法:

public async Task<IEnumerable<Event>> Handle(GetEventsByClientIdAndProjectIdQuery query, CancellationToken cancellationToken)
{
    Expression<Func<Event, int?>> clientId = (s => query.ClientId);
    Expression<Func<Event, int?>> projectId = (s => query.ProjectId);
    Expression<Func<Event, int?>> eventTypeId = (s => query.EventTypeId);

    if (query.ProjectId.HasValue)
    {
        projectId = (p => p.ProjectId.Equals(query.ClientId)); //error: cannot implicitly convert type bool to int?
    }

    if (query.EventTypeId.HasValue)
    {
        eventTypeId = (e => e.EventTypeId == query.EventTypeId.Value);
    }

    var evts = await _context.Events.Where(clientId) //error: Argument 2: cannot convert from 'System.Linq.Expressions.Expression<System.Func<UNW.Domain.Entities.Event, int?>>' to 'System.Func<UNW.Domain.Entities.Event, bool>'
                                    .Where(projectId)
                                    .Where(eventTypeId)
                                    .ToListAsync();
                
                

    if (evts == null)
        return null;

    return evts.AsReadOnly();
}



还有我的GetEventsByClientIdAndProjectIdQuery 模特:

public int? ProjectId { get; set; }
public int? ClientId { get; set; }
public int? EventTypeId { get; set; }

我错过了什么?

【问题讨论】:

    标签: c# linq .net-core asp.net-core-webapi


    【解决方案1】:

    你可以让它更简单

    public async Task<IEnumerable<Event>> Handle(GetEventsByClientIdAndProjectIdQuery query, 
        CancellationToken cancellationToken)
    {
        var dbQuery = _context.Events;
        if (query.ProjectId.HasValue)
        {
            dbQuery = dbQuery.Where(p => p.ProjectId.Equals(query.ClientId));
        }
        if (query.EventTypeId.HasValue)
        {
            dbQuery = dbQuery.Where(e => e.EventTypeId == query.EventTypeId.Value);
        }
        //same goes for projectID which is missing from your question
    
        var evts = await dbQuery.ToListAsync();
                    
        //evts will nerver be null, you might want do something for evts.Count==0
        //but it is fine to return an empty list
    
        return evts.AsReadOnly();
    }
    

    【讨论】:

    • 您可以删除对 null 的检查。 ToListAsync 从不返回 null。
    【解决方案2】:

    我能想到的最简洁的解决方案

    public async Task<IEnumerable<Event>> Handle(GetEventsByClientIdAndProjectIdQuery query, CancellationToken cancellationToken)
      => await _context.Events
            .Where(evt => evt.ClientId.Equals(query.ClientId))
            .Where(evt => query.ProjectId.HasValue ? evt.ProjectId.Equals(query.ProjectId.Value) : true)
            .Where(evt => query.EventTypeId.HasValue ? evt.EventTypeId.Equals(query.EventTypeId.Value) : true)
            .ToListAsync(cancellationToken)
            .AsReadOnly();             
    

    如果提供了过滤器
    那么使用它
    否则不过滤掉元素

    【讨论】:

      【解决方案3】:

      我喜欢并且喜欢@Magnetron 的简单回答,但要基于您现有的代码:

      //error: cannot implicitly convert type bool to int?
      

      问题 1:clientIdprojectIdeventTypeId 的签名都设置为返回一个可为空的 int (Func.Equals() 返回一个布尔值。

      假设我了解您想要完成的任务,您可以尝试以下更新:

      // 1. Change the return values from int? to boolean.
      // 2. Go ahead and set your expression to return Events where the ClientId is equal
      //    to the ClientId passed in with your query parameter
      Expression<Func<Event, bool>> clientId = 
                                       (s => s.ClientId.Equals(query.ClientId));
      
      // 3. Similar to the above with ClientId, but we also include the guard clauses for the optional parameters (ProjectId and EventTypeId)
            
      Expression<Func<Event, bool>> projectId = 
                                       (s => (!query.ProjectId.HasValue || query.ProjectId == 0) || s.ID.Equals(query.ProjectId));
      Expression<Func<Event, bool>> eventTypeId = 
                                       (s => (!query.EventTypeId.HasValue || query.EventTypeId == 0) || s.ID.Equals(query.EventTypeId));
      
      // (Issue 2 with clientId resolved by the updates made to resolve Issue 1)
      var evts = await _context.Events.Where(clientId) 
                                      .Where(projectId)
                                      .Where(eventTypeId)
                                      .ToListAsync();
                  
                  
      if (evts == null)
          return null;
      
      return evts.AsReadOnly();
      

      【讨论】:

        猜你喜欢
        • 2017-09-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-08-29
        • 1970-01-01
        • 1970-01-01
        • 2016-02-28
        • 1970-01-01
        相关资源
        最近更新 更多