вдохновленный этим ответомЯ пытаюсь сопоставить свойство класса модели с выражением, основанным на фактическом объекте. Вот два задействованных класса:
public class Customer
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Id { get; set; }
public DateTime? BirthDate { get; set; }
public int CustomerTypeId { get; set; }
}
public class CustomerModel
{
...
public bool HasEvenId { get; set; }
}
Пример возможного выражения, которое я хотел бы преобразовать:
Expression> from = model => model.HasEvenId;
Expression> to = entity => ((entity.Id % 2) == 0);
Проблема в том, что мне нужно предоставить конечную точку OData через ASP.NET WebAPI, но мне нужно выполнить некоторые операции. на сущности, прежде чем я смогу их, отсюда потребность в классе модели и необходимость перевода выражения на основе модели, которую я мог бы получить как запрос OData в выражении, основанном на сущности, которую я бы использовал для запроса EF4.
Вот где я дошел до сих пор:
private static readonly Dictionary Mappings = GetMappings();
private static Dictionary GetMappings()
{
var mappings = new Dictionary();
var mapping = GetMappingFor((CustomerModel model) => model.HasEvenId, (Customer customer) => (customer.Id%2) == 0);
mappings.Add(mapping.Item1, mapping.Item2);
return mappings;
}
private static Tuple GetMappingFor(Expression> fromExpression, Expression> toExpression)
{
MemberExpression fromMemberExpression = (MemberExpression) fromExpression.Body;
return Tuple.Create(fromMemberExpression, toExpression);
}
public static Expression> Translate(Expression> expression, Dictionary mappings = null)
{
if (expression == null)
return null;
string parameterName = expression.Parameters[0].Name;
parameterName = string.IsNullOrWhiteSpace(parameterName) ? "p" : parameterName;
var param = Expression.Parameter(typeof(TTo), parameterName);
var subst = new Dictionary { { expression.Parameters[0], param } };
ParameterChangeVisitor parameterChange = new ParameterChangeVisitor(parameterName);
if (mappings != null)
foreach (var mapp in mappings)
subst.Add(mapp.Key, parameterChange.Visit(mapp.Value));
var visitor = new TypeChangeVisitor(typeof(TFrom), typeof(TTo), subst);
return Expression.Lambda>(visitor.Visit(expression.Body), param);
}
public IQueryable Get()
{
var filterExtractor = new ODataFilterExtractor();
Expression> expression = filterExtractor.Extract(Request);
Expression> translatedExpression = Translate(expression, Mappings);
IQueryable query = _context.Customers;
if (translatedExpression != null)
query = query.Where(translatedExpression);
var finalQuery = from item in query.AsEnumerable()
select new CustomerModel()
{
FirstName = item.FirstName,
LastName = item.LastName,
Id = item.Id,
BirthDate = item.BirthDate,
CustomerTypeId = item.CustomerTypeId,
HasEvenId = (item.Id % 2 ) == 0
};
return finalQuery.AsQueryable();
}
где:
Кроме того, я изменил метод VisitMember ответа, указанного выше, следующим образом:
protected override Expression VisitMember(MemberExpression node)
{
// if we see x.Name on the old type, substitute for new type
if (node.Member.DeclaringType == _from)
{
MemberInfo toMember = _to.GetMember(node.Member.Name, node.Member.MemberType, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).SingleOrDefault();
if (toMember != null)
{
return Expression.MakeMemberAccess(Visit(node.Expression), toMember);
}
else
{
if (_substitutions.Select(kvp => kvp.Key).OfType().Any(me => me.Member.Equals(node.Member)))
{
MemberExpression key = _substitutions.Select(kvp => kvp.Key).OfType().Single(me => me.Member.Equals(node.Member));
Expression value = _substitutions[key];
// What to return here?
return Expression.Invoke(value);
}
}
}
return base.VisitMember(node);
}
Спасибо за помощь.