Консолидация или повторное использование выражения LINQ

У меня есть выражение LINQ, которое используется в качестве фильтра в инструкции LINQ to SQL, где предложение. Моя проблема в том, что выражение 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);
    }
}

person sipsorcery    schedule 29.10.2010    source источник


Ответы (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();
person Devart    schedule 29.10.2010
comment
Я не думаю, что L2S может перевести switch в SQL. - person Matt Kocaj; 29.02.2012