【问题标题】:Consolidate or reuse LINQ expression合并或重用 LINQ 表达式
【发布时间】:2012-06-13 15:23:23
【问题描述】:

我有一个 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);
    }
}

【问题讨论】:

    标签: c# linq linq-to-sql linq-expressions


    【解决方案1】:

    尝试以下方法:

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

    【讨论】:

    • 我认为 L2S 不能将 switch 转换为 SQL。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-08-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多