inspiriert von this answer Ich versuche, eine Eigenschaft einer Modellklasse einem Ausdruck zuzuordnen, der auf der tatsächlichen Entität basiert. Dies sind die beiden beteiligten Klassen:Übersetzen der Ausdrucksbaumstruktur von einem Typ in einen anderen Typ mit komplexen Zuordnungen
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; }
}
Ein Beispiel für einen möglichen Ausdruck Ich mag würde konvertieren ist:
Expression<Func<CustomerModel, bool>> from = model => model.HasEvenId;
Expression<Func<Customer, bool>> to = entity => ((entity.Id % 2) == 0);
Das Problem ist, dass ich einen OData-Endpunkt über ASP belichten. NET WebAPI, aber ich muss einige Operationen an den Entitäten vornehmen, bevor ich sie ausführen kann, daher die Notwendigkeit einer Modellklasse und die Notwendigkeit, den Ausdruck basierend auf dem Modell zu übersetzen, das ich als OData-Abfrage in einem Ausdruck basierend auf der Entität erhalten könnte , die ich verwenden würde, um EF4 abzufragen.
Dies ist, wo ich so weit gekommen:
private static readonly Dictionary<Expression, Expression> Mappings = GetMappings();
private static Dictionary<Expression, Expression> GetMappings()
{
var mappings = new Dictionary<Expression, Expression>();
var mapping = GetMappingFor((CustomerModel model) => model.HasEvenId, (Customer customer) => (customer.Id%2) == 0);
mappings.Add(mapping.Item1, mapping.Item2);
return mappings;
}
private static Tuple<Expression, Expression> GetMappingFor<TFrom, TTo, TValue>(Expression<Func<TFrom, TValue>> fromExpression, Expression<Func<TTo, TValue>> toExpression)
{
MemberExpression fromMemberExpression = (MemberExpression) fromExpression.Body;
return Tuple.Create<Expression, Expression>(fromMemberExpression, toExpression);
}
public static Expression<Func<TTo, bool>> Translate<TFrom, TTo>(Expression<Func<TFrom, bool>> expression, Dictionary<Expression, Expression> 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, Expression> { { 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<Func<TTo, bool>>(visitor.Visit(expression.Body), param);
}
public IQueryable<CustomerModel> Get()
{
var filterExtractor = new ODataFilterExtractor<CustomerModel>();
Expression<Func<CustomerModel, bool>> expression = filterExtractor.Extract(Request);
Expression<Func<Customer, bool>> translatedExpression = Translate<CustomerModel, Customer>(expression, Mappings);
IQueryable<Customer> 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();
}
wo:
- ODataFilterExtractor eine Klasse, die die $ Filterausdruck aus dem RequestMessage extrahieren wir empfangen;
- ParameterChangeVisitor ändert nur alle ParameterExpression in eine neue mit der angegebenen Zeichenfolge als Parametername;
Außerdem änderte ich die VisitMember Methode der Antwort oben auf diese Weise verbunden:
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<MemberExpression>().Any(me => me.Member.Equals(node.Member)))
{
MemberExpression key = _substitutions.Select(kvp => kvp.Key).OfType<MemberExpression>().Single(me => me.Member.Equals(node.Member));
Expression value = _substitutions[key];
// What to return here?
return Expression.Invoke(value);
}
}
}
return base.VisitMember(node);
}
Dank für das Ihnen helfen.
Nun, du bist wirklich mutig! Implementieren eines Linq-Anbieters alle selbst ... – Aliostad
Konnten Sie Ihren wolligen Satz umwandeln _Das Problem ist (...), EF4._ zu einer klaren, prägnanten Frage abzufragen? Markieren Sie den Code wo Sie Hilfe benötigen? –
ich denke, ein Besucher die Arbeit machen könnte – Proviste