Сначала: мы не делаем TPH (таблица на иерархию), что значительно упростит эту задачу.
У меня около 20 POCO, которые в некоторых случаях имеют схожие свойства.,Мне нравятся похожие свойства ___.CreatedDate
и ___.UpdatedDate
.Для некоторых POCO UpdatedDate
не имеет смысла, поэтому у них нет этого свойства.CreatedDate
будет существовать всегда, UpdatedDate
может быть нулевым.Иногда есть и третье поле.
Запрос на получение объектов из базы данных всегда выглядит одинаково, независимо от того, какой из 20 POCO я запрашиваю.Однако запрос дублировался 20 раз, по одному для каждого типа объекта.Мне удалось выделить часть извлечения для метода расширения (от IDbSet<T>
), чтобы выполнить первоначальный поиск и объединения, оставив фильтрацию диапазона дат в качестве упражнения для потребителя.Теперь я хочу объединить 20 фильтров с практически одинаковым диапазоном дат в один, но у меня возникают проблемы с пониманием запросов.
Логика фильтрации дат, согласно POCO, заключается в том, что UpdatedDate необходимо проверить и сравнить его значениедо порога.Если UpdatedDate был нулевым (или свойство не существовало), то вместо этого следует использовать CreatedDate.
Я начал с создания метода получения статических свойств для каждого POCO, который яназванный "DateFields".Он набирается как IEnumerable<Expression<Func<T, DateTime?>>>
, который выглядит следующим образом:
get
{
yield return x => x.UpdatedDate;
yield return x => x.CreatedDate;
yield return x => x.Date;
}
Эти поля возвращаются в том порядке, в котором я хочу их проверять, и являются уникальными для каждого POCO.
Затем я создалпредикат для проверки каждого значения в верхнем и нижнем диапазонах:
public static bool DatesBetween<T> (T value, IEnumerable<Expression<Func<T, DateTime?>>> dates, DateTime? dateFrom, DateTime? dateTo)
{
var firstDate = dates
.Select(expression => expression.Compile())
.FirstOrDefault(func => func(value) != null);
if (firstDate == null)
return false;
var minDate = dateFrom.GetValueOrDefault(SqlDateTime.MinValue.Value);
var maxDate = dateTo.GetValueOrDefault(SqlDateTime.MaxValue.Value);
var actualDate = firstDate(value);
return (minDate <= actualDate && actualDate <= maxDate);
}
Однако, как и ожидалось, когда я пытаюсь использовать это в своем IQueryable
, я получаю исключение времени выполнения, потому что нет преобразования в DatesBetweenв SQL.Я надеялся, что, сохранив дерево выражений, я смогу ... я не знаю ... держать EF счастливым.Все это используется следующим образом:
return Entities
.GetEntitiesBySomeField(field := "magic value")
.Where(entity => RepositoryExtensions.DatesBetween(entity, MyPOCO.MyDates, dateFrom, dateTo));
Это то, что я спрашиваю, ясно, и есть ли способ выполнить этот тип общей фильтрации без выполнения AsEnumerable () (который работает, но нене выполнить мою задачу фильтрации по БД).