У меня много классов
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;
но я получаю идентификатор типа, но мне нужен маркер
Вы можете решить эту проблему менее принудительно (чем использовать 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);
Использовать Enumerable.OfType
var testQuery = db.Markers.Where(lessOldDate).OfType<Marker>().ToList();
Используйте метод Cast
:
var testQuery=db.Markers.Where(lessOldDate).Cast<Marker>();
также см. этот связанный вопрос.