如何在不使用If条件的情况下减少此方法?

时间:2019-12-17 14:46:52

标签: c# entity-framework filter

我正在尝试使用实体框架过滤我的GET方法...如果条件有效,请使用

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

它起作用了。...我认为我在处理表中的外键问题时遇到了麻烦...

5 个答案:

答案 0 :(得分:1)

有一种非常有趣的方法,可将多个布尔值(包含或不包含等)仅包含一个值。这称为按位操作。此处:Most common C# bitwise operations on enums 您可以找到使用这种“技术”的不同方法。

答案 1 :(得分:1)

它返回null,因为您不检查Account属性是否为null。

 AccountName = x.Account.Name

因此,以上内容将引发Null引用异常。

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

AccountName = x.Account?.Name

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

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

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

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

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

答案 2 :(得分:1)

您似乎需要&&运算符:

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

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

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

答案 3 :(得分:0)

我认为使用if是添加过滤器的一种非常清晰的方法。但是,您应该将result设为IQueryable,而不是具体化您希望在sql服务器上执行过滤器的查询。
因此删除.ToListAsync().ConfigureAwait(false);

var result = await _readRepository...

if(...)
  return result.Where(x => ...).ToListAsync().ConfigureAwait(false);

return result.ToListAsync().ConfigureAwait(false);

答案 4 :(得分:0)

好吧,显然,我的问题是x.Account.Name之后的Auth::user()我不能使用ToString()...我不知道为什么,但是现在没有if条件就可以工作

Auth::hasUser()

如果有人知道它为什么起作用,我会很感激