【问题标题】:How can I reduce this method without using the If condition?如何在不使用 If 条件的情况下减少此方法?
【发布时间】:2020-04-10 02:23:45
【问题描述】:

我正在尝试使用实体框架来过滤我的 GET 方法...使用 if 条件它正在工作

 public async Task<List<TimeEntryViewModel>> Get(TimeEntryFilter filter)
        {
            var result = await _readRepository
                .FindByCondition(x => x.IsApproved == true)
                .Include(x => x.Task)
                .Include(x => x.Account)
                .Select(x => new TimeEntryViewModel
                {
                    AccountName = x.Account.Name,
                    Date = x.Date,
                    StartTime = x.StartTime,
                    FinishTime = x.FinishTime,
                    InternalId = x.InternalId,
                    TaskId = x.TaskId,
                    TaskName = x.Task.Name,
                    CreatedBy = x.CreatedBy,
                    CustomerName = x.Task.Project.ServiceOrder.Customer.Name
                }).ToListAsync().ConfigureAwait(false);

            if  (filter.AccountName != null || 
                (filter.StartDate.HasValue && filter.FinishDate.HasValue && (filter.StartDate <= filter.FinishDate)) ||
                (filter.TaskName != null) ||
                (filter.CustomerName != null) ||
                (filter.InternalId != null))
                result = result.Where(x => 
                                        (x.AccountName.ToString().Contains(filter.AccountName)) &&
                                        (x.Date >= filter.StartDate && x.Date <= filter.FinishDate) &&
                                        (x.CustomerName.ToString().Contains(filter.CustomerName)) &&
                                        (x.TaskName.ToString().Contains(filter.TaskName)) &&
                                        (x.InternalId.ToString().Contains(filter.InternalId.ToString()))).ToList();

            return result;
        }

但我想有一种方法可以在不使用 if 的情况下改进此方法

我已经尝试过这样做(只需过滤帐户名称以显示) 但返回内部服务器错误

var result = await _readRepository
                .FindByCondition(x => x.IsApproved == true)
                .Where(x => string.IsNullOrEmpty(filter.AccountName) || x.Account.Name.ToString().Contains(filter.AccountName))
                .Include(x => x.Task)
                .Include(x => x.Account)
                .Select(x => new TimeEntryViewModel
                {
                    Id = x.Id,
                    AccountName = x.Account.Name,
                    Date = x.Date,
                    Description = x.Description,
                    StartTime = x.StartTime,
                    FinishTime = x.FinishTime,
                    InternalId = x.InternalId,
                    OnSite = x.OnSite,
                    IsApproved = x.IsApproved,
                    IsBillable = x.IsBillable,
                    TaskId = x.TaskId,
                    TaskName = x.Task.Name,
                    CreatedBy = x.CreatedBy,
                    CustomerName = x.Task.Project.ServiceOrder.Customer.Name
                }).ToListAsync().ConfigureAwait(false);

好的,伙计们 EDIT1:在我的第二个示例中,使用 InternalId 而不是 Account.Name

.Where(x => (string.IsNullOrEmpty(filter.InternalId.ToString())) || x.InternalId.ToString().Contains(filter.InternalId.ToString()))

它有效....我相信我在处理表中的外键时遇到了麻烦...

【问题讨论】:

    标签: c# entity-framework filter


    【解决方案1】:

    好吧,显然,我的问题是 .Where(x =&gt; string.IsNullOrEmpty(filter.AccountName) || x.Account.Name.ToString().Contains(filter.AccountName)) 在 x.Account.Name 之后我不能使用 ToString()...我不知道确切原因,但现在没有 if 条件也可以工作

    public async Task<List<TimeEntryViewModel>> GetApproved(TimeEntryFilter filter)
            {
                var result = await _readRepository
                    .FindByCondition(x => x.IsApproved == true)
                    .Include(x => x.Task)
                    .Include(x => x.Account)
                    .Where(x => 
                                (string.IsNullOrEmpty(filter.InternalId.ToString()) || x.InternalId.ToString().Contains(filter.InternalId.ToString())) &&
                                (string.IsNullOrEmpty(filter.AccountName) || x.Account.Name.Contains(filter.AccountName)) && 
                                (string.IsNullOrEmpty(filter.CustomerName) || x.Task.Project.ServiceOrder.Customer.Name.Contains(filter.CustomerName)) &&
                                (string.IsNullOrEmpty(filter.TaskName) || x.Task.Name.Contains(filter.TaskName)))
                    .Select(x => new TimeEntryViewModel
                    {
                        Id = x.Id,
                        AccountName = x.Account.Name,
                        Date = x.Date,
                        Description = x.Description,
                        StartTime = x.StartTime,
                        FinishTime = x.FinishTime,
                        InternalId = x.InternalId,
                        OnSite = x.OnSite,
                        IsApproved = x.IsApproved,
                        IsBillable = x.IsBillable,
                        TaskId = x.TaskId,
                        TaskName = x.Task.Name,
                        CreatedBy = x.CreatedBy,
                        CustomerName = x.Task.Project.ServiceOrder.Customer.Name
                    }).ToListAsync().ConfigureAwait(false);
    
                return result;
            }
    

    如果有人知道它为什么起作用,我将不胜感激

    【讨论】:

      【解决方案2】:

      看来您需要&amp;&amp; 运算符:

      .Where(x => string.IsNullOrEmpty(filter?.AccountName) 
          && x?.Account?.Name.ToString().Contains(filter.AccountName))
      

      因为当您使用|| 运算符时,您可以在Where 的表达式的第二部分中得到NullReferenceException

      x?.Account?.Name.ToString().Contains(filter.AccountName))
      

      【讨论】:

      • 但是这样我就得不到正确的SQL表达式了
      【解决方案3】:

      它返回 null 是因为您没有检查 Account 属性是否为 null。

       AccountName = x.Account.Name
      

      所以上面会抛出一个空引用异常。

      避免这种情况的一种方法是使用null conditional operator

      AccountName = x.Account?.Name
      

      您也可以对以下属性采用相同的方法:

      • Task.Name
      • Task.Project.ServiceOrder.Customer.Name

      并使用相同的运算符安全地访问它们,如下所示:

      • Task?.Name
      • Task?.Project?.ServiceOrder?.Customer?.Name

      基于以上内容,您可以按照您对AccountName 属性已经采用的方式进行操作,但同时您也可以使用空条件运算符。

      【讨论】:

      • 如果我更改为第二种方式,我收到错误表达式树 lambda 可能不包含空传播运算符。
      【解决方案4】:

      有一种非常有趣的方法可以将多个布尔值(包含或不包含等)集中在一个值上。它被称为按位运算。这里:Most common C# bitwise operations on enums 您可以找到这种“技术”的不同方法。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-02-28
        • 1970-01-01
        • 2017-09-10
        • 1970-01-01
        • 2019-03-06
        • 1970-01-01
        • 1970-01-01
        • 2016-02-13
        相关资源
        最近更新 更多