#c_sharp #entity_framework #linq
public class BaseEntity { public int Id {get;set;} public DateTime Created {get;set;} public bool IsDeleted {get;set;} } Думаю данные свойства есть почти в каждой сущности, и довольно часто Возникает необходимость получить список за период, т.е. что то типа такого: var start = new DateTime(2015, 11, 01); var stop = new DateTime(2015, 11, 30); var results = context.Entity.Where(x=>x.Created>=start&&x.Created<=stop).ToList() но довольно часто таких сущностей несколько и плодить по сути однообразный код крайне не хочется, другой пример получить строки где какое то значение равно заданному, т.е. что то типа этого: var arg = true; var results = context.Entity.Where(x=>x.IsDeleted==arg).ToList(); и это встречается тоже довольно часто ну и т.д. т.е. хочется что то типа этого: var start = new DateTime(2015, 11, 01); var stop = new DateTime(2015, 11, 30); var results = context.Entity.Beetwen("Created",start,stop).ToList(); public static class BaseEntityExtensions { //где field это имя поля по которому надо фильтровать записи public static IQueryableBeetwen(this IQueryable src, string field, DateTime start, DateTime stop) { //Здесь надеюсь пока неизвестная мне *магия* } } Помогите реализовать метод Beetwen
Ответы
Ответ 1
Where метод для IQueryable принимает Expression поэтому его можно собрать самостоятельно public static IQueryableBeetwen (this IQueryable src, string field, DateTime start, DateTime stop) where T: BaseEntity { var p = Expression.Parameter(typeof(T)); // Param_0 var prop = Expression.PropertyOrField(p, field); //Param_0.field var startExpr = Expression.Constant(start); var stopExpr = Expression.Constant(stop); var firstCondition = Expression.GreaterThanOrEqual(prop, startExpr); // Param_0.field >= start var secondCondition = Expression.LessThanOrEqual(prop, stopExpr); // Param_0.field <= stop var fullExpression = Expression.AndAlso(firstCondition, secondCondition); // Param_0.field >= start && Param_0.field <= stop var func = Expression.Lambda >(fullExpression,p); // Param_0 => Param_0.field >= start && Param_0.field <= stop return src.Where(func); } Методы которые использовались: Expression.Parameter Expression.PropertyOrField Expression.Constant Expression.GreaterThanOrEqual Expression.LessThanOrEqual Expression.AndAlso Expression.Lambda Альтернативным подходом может быть использование библиотеки DynamicLinq (есть в NuGet) в ней можно передавать в функции не Expression, а строку src.Where(string.Format("{0} >= @0 && {0} <= @1", field), start, stop); По мотивам ответа @Vlad, только используя уже переданное выражение public static IQueryable Beetwen (this IQueryable src, Expression > propertyExpression, DateTime from, DateTime to) { var fromCondition = Expression.GreaterThanOrEqual(propertyExpression.Body, Expression.Constant(from)); var toCondition = Expression.LessThanOrEqual(propertyExpression.Body, Expression.Constant(to)); return src.Where(Expression.Lambda >(Expression.And(fromCondition, toCondition), propertyExpression.Parameters.First())); } в использовании: var res = query.Beetwen(_ => _.Date, from, to); И еще вариант, но не такой интересный как предыдущие public static IQueryable Beetwen (this IQueryable src, Expression > propertyExpression, DateTime from, DateTime to) { Expression > func = d => d >= from && d <= to; return src.Where(Expression.Lambda >(Expression.Invoke(func, propertyExpression.Body), propertyExpression.Parameters.First())); } в использовании: var res = query.Beetwen(_ => _.Date, from, to); немного обобщенный вариант public static IQueryable Beetwen (this IQueryable src, Expression > propertyExpression, U from, U to) { var fromCondition = Expression.GreaterThanOrEqual(propertyExpression.Body, Expression.Constant(from)); var toCondition = Expression.LessThanOrEqual(propertyExpression.Body, Expression.Constant(to)); return src.Where(Expression.Lambda >(Expression.And(fromCondition, toCondition), propertyExpression.Parameters.First())); } в использовании: var res = query.Beetwen(_ => _.Date, from, to); Ответ 2
Я бы посоветовал использовать решение, которое поддается рефакторингу. И передавать в метод не имя свойства, а выражение. public static IQueryableBeetwen (this IQueryable src, Expression > propertyExpression, DateTime from, DateTime to) { var parameterExpr = Expression.Parameter(typeof(T)); var parameterizedPropertyExpr = Expression.PropertyOrField(parameterExpr, ((MemberExpression)propertyExpression.Body).Member.Name); var fromCondition = Expression.GreaterThanOrEqual(parameterizedPropertyExpr, Expression.Constant(from)); var toCondition = Expression.LessThanOrEqual(parameterizedPropertyExpr, Expression.Constant(to)); return src.Where(Expression.Lambda >(Expression.And(fromCondition, toCondition), parameterExpr)); } В этом случае метод можно вызывать вот так: var res = query.Beetwen(_ => _.Date, from, to);
Комментариев нет:
Отправить комментарий