Как написать универсальный, где для нескольких типов в linq для сущностей?

1

У меня много классов

public class City
{
    public int CityID { get; set; }
    public string Name { get; set; }
    public string Comment { get; set; }
    public virtual ICollection<ApplicationUser> DryCleanings { get; set; }
    public DateTime DateCreated { get; set; }
    public DateTime DateChanged { get; set; }
    public bool IsDeleted { get; set; }
}

    public class Marker
{
    public int MarkerID { get; set; }
    public string Name { get; set; }
    public string Comment { get; set; }
    public byte[] Icon { get; set; }
    public virtual IEnumerable<ApplicationUser> Cleanings { get; set; }
    public DateTime DateCreated { get; set; }
    public DateTime DateChanged { get; set; }
    public bool IsDeleted { get; set; }
}
.
.
.

Все они имеют одинаковые три свойства

    public DateTime DateCreated { get; set; }
    public DateTime DateChanged { get; set; }
    public bool IsDeleted { get; set; }

Мне нужно написать то же самое, где запрос для каждого из них, что-то вроде этого

_db.Cities.Where(c => !c.IsDeleted && c.DateChanged > oldDate && c.DateChanged < oldDate);
_db.Markers.Where(m => !m.IsDeleted && m.DateChanged > oldDate && m.DateChanged < oldDate);

Я не хочу писать этот запрос для каждого класса. Могу ли я написать этот предикат один раз и использовать для всех?

пс. Я пробовал унаследовать от интерфейса

    public interface IDate
{
    public DateTime DateCreated { get; set; }
    public DateTime DateChanged { get; set; }
    public bool IsDeleted { get; set; }
}

и напишите что-нибудь вроде этого

 Expression<Func<IDate, bool>> lessOldDate = c => !c.IsDeleted && c.DateChanged > oldDate && c.DateChanged < oldDate;

но я получаю идентификатор типа, но мне нужен маркер

Изображение 174551

Теги:
reflection
entity-framework
entity-framework-6

3 ответа

3
Лучший ответ

Вы можете решить эту проблему менее принудительно (чем использовать Enumerable.Cast или Enumerable.OfType), определив общий метод:

public static IQueryable<T> WhereLessOld<T>(this IQueryable<T> source, DateTime oldDate)
    where T : IDate
{
    return source.Where(c => !c.IsDeleted && c.DateChanged > oldDate && c.DateChanged < oldDate);
}

Примечание. Возможно, проблема с кодом выше, если поставщик LINQ, который вы используете, неправильно обрабатывает интерфейсы - в этом случае вы можете использовать следующий код:

using System;
using System.Linq;
using System.Linq.Expressions;

public static IQueryable<T> WhereLessOld<T>(this IQueryable<T> source, DateTime oldDate)
    where T : IDate
{
    var param = Expression.Parameter(typeof(T));
    var filterExpression =
        Expression.And(
            Expression.Not(Expression.Property(param, "IsDeleted")),
            Expression.And(
                Expression.GreaterThan(
                    Expression.Property(param, "DateChanged"),
                    Expression.Constant(oldDate)
                ),
                Expression.LessThan(
                    Expression.Property(param, "DateChanged"),
                    Expression.Constant(oldDate)
                )
            )
        );
    var delegateExpression = Expression.Lambda<Func<T, bool>>(filterExpression, param);

    return source.Where(delegateExpression);
}

И тогда вы можете написать:

var testQuery = db.Markers.WhereLessOld(oldDate);
  • 0
    Мне нравится это решение.
2

Использовать Enumerable.OfType

var testQuery = db.Markers.Where(lessOldDate).OfType<Marker>().ToList();
1

Используйте метод Cast:

var testQuery=db.Markers.Where(lessOldDate).Cast<Marker>();

также см. этот связанный вопрос.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню