代码之家  ›  专栏  ›  技术社区  ›  sipsorcery

合并或重用Linq表达式

  •  1
  • sipsorcery  · 技术社区  · 14 年前

    我有一个LINQ表达式,它在LINQ to SQL语句的WHERE子句中用作文件管理器。我的问题是linq-to-sql表达式变得笨拙,而且它包含的逻辑最终在多个位置违反了dry(这是我第三次处理由qa引起的错误,因为它不同步)。

    是否有任何方法可以重用像下面这样的LINQ表达式或将其分解为较小的子表达式?我最大的问题是,由于表达式用于Linq to SQL调用,它不能使用任何其他类或方法,因为Linq to SQL库不知道如何将它们表示为SQL。

    public static Expression<Func<MyClass, bool>> MyClassFilterExpression
    {
        get
        {
            return x => (x.Status.Count > 0 && x.Status.Any(y => y.StatusID == 5)) ? "Refused" :
                (x.Status.Count > 0 && x.Status.Any(y => y.StatusID == 6)) ? "Cancelled" :
                    (x.DateTimeExpired.HasValue && DateTime.Today > x.DateTimeExpired.Value) ? "Expired" :
                        (x.Duration.HasValue && x.DurationTypeID.HasValue && x.DateTimeApproved.HasValue) ?
                            (x.DurationTypeID == (int)DurationTypes.Day && DateTime.Today > x.DateTimeApproved.Value.AddDays(x.Duration.Value)) ? "Expired" :
                                (x.Status.Count > 0 && x.Status.Any(y => y.StatusID == 4 || y.StatusID == 10)) ? "Approved" : "Pending").Contains(filterValue);
        }
    }
    

    理想情况下,我想做的是下面这样的事情。它不起作用,因为linq to sql不能表示getstatus()方法。希望还有其他聪明的方法可以做到?

    public ReviewStatuses GetStatus(DateTime? dateTimeExpired, int? reviewStatusID)
    {
        var isExpired = (dateTimeExpired.HasValue && DateTime.Today >= dateTimeExpired.Value.Date);
    
        if (reviewStatusID == ReviewStatuses.Cancelled.GetHashCode())
        {
            return ReviewStatuses.Cancelled;
        }
        else if (reviewStatusID == ReviewStatuses.Refused.GetHashCode())
        {
            return ReviewStatuses.Refused;
        }
        return ReviewStatuses.Pending;
    }
    
    public static Expression<Func<MyClass, bool>> MyClassFilterExpression
    {
        get
        {
            return x => x.Status.Count > 0 && x.Status.Any(y => GetStatus(y.DateTimeExpired, y.StatusID)).Contains(filterValue);
        }
    }
    
    1 回复  |  直到 14 年前
        1
  •  1
  •   Devart    14 年前

    尝试如下操作:

    public static Expression<Func<MyClass, bool>> GetMyClassFilterExpression(string filterValue) {
    
      if (filterValue == "Refused")
        return x => (x.Status.Count > 0 && x.Status.Any(y => y.StatusID == 5));
      else if (filterValue == "Cancelled")
        return x => (x.Status.Count > 0 && x.Status.Any(y => y.StatusID == 6));
      else if (filterValue == "Expired")
        return x => (x.DateTimeExpired.HasValue && DateTime.Today > x.DateTimeExpired.Value) ||
          (x.DurationTypeID == (int)DurationTypes.Day && DateTime.Today > x.DateTimeApproved.Value.AddDays(x.Duration.Value));
      else if (filterValue == "Approved")
        return x => (x.Status.Count > 0 && x.Status.Any(y => y.StatusID == 4 || y.StatusID == 10));
      // and so on...
      else
        throw new ArgumentException("Your message.");
    }
    
    ....
    
    string filterValue = "Refused";
    Expression<Func<MyClass, bool>> whereCluase = GetMyClassFilterExpression(filterValue);
    var list = dataContext.MyClasses.Where(whereCluase).ToList();