合并或重用 LINQ 表达式

发布于 2024-09-29 20:44:51 字数 2009 浏览 5 评论 0原文

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

I have a LINQ expression that gets used as a filer in a LINQ to SQL statement where clause. My problem is that the LINQ to SQL expression has become unwieldy and also the logic it contains has ended up in multiple locations violating DRY (this is the 3rd time I'm working on a bug raised by QA for it getting out of sync).

Is there any way I can reuse a LINQ expression like the one below or decompose it into smaller sub-expressions? My biggest issue is that because the expression is used in a LINQ to SQL call it cannot use any other classes or methods since the LINQ to SQL library doesn't won't know how to express them as 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);
    }
}

Ideally what I'd like to be able to do is something like the below. It doesn't work because LINQ to SQL can't express the GetStatus() method. Hopefully there is some other clever way to do it?

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

甜警司 2024-10-06 20:44:51

尝试如下操作:

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

Try something like the following:

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();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文