gpt4 book ai didi

linq - 使用复杂的映射将表达式树从一种类型转换为另一种类型

转载 作者:行者123 更新时间:2023-12-04 18:12:31 25 4
gpt4 key购买 nike

灵感来自 this answer我正在尝试将模型类上的属性映射到基于实际实体的表达式。
这是涉及的两个类:

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<Func<CustomerModel, bool>> from = model => model.HasEvenId;
Expression<Func<Customer, bool>> to = entity => ((entity.Id % 2) == 0);

问题是我必须通过 ASP.NET WebAPI 公开一个 OData 端点,但我需要先对实体进行一些操作,然后才能使用它们,因此需要一个模型类,并且需要根据模型转换表达式我可以在基于实体的表达式中作为 OData 查询接收,我将使用它来查询 EF4。

这是我到目前为止的地方:
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();
}

在哪里:
  • ODataFilterExtractor 是一个从我们收到的 RequestMessage 中提取 $filter 表达式的类;
  • ParameterChangeVisitor 只是将所有 ParameterExpression 更改为以提供的字符串作为参数名称的新参数;

  • 另外,我以这种方式更改了上面链接的答案的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<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);
    }

    谢谢你的帮助。

    最佳答案

    我冒昧地修改了您的代码,但这确实有用,

    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 string FullName { get; set; }
    public bool HasEvenId { get; set; }
    }

    sealed class AToBConverter<TA, TB> : ExpressionVisitor
    {
    private readonly Dictionary<ParameterExpression, ParameterExpression> _parameters = new Dictionary<ParameterExpression, ParameterExpression>();
    private readonly Dictionary<MemberInfo, LambdaExpression> _mappings;

    protected override Expression VisitParameter(ParameterExpression node)
    {
    if (node.Type == typeof(TA))
    {
    ParameterExpression parameter;
    if (!this._parameters.TryGetValue(node, out parameter))
    {
    this._parameters.Add(node, parameter = Expression.Parameter(typeof(TB), node.Name));
    }
    return parameter;
    }
    return node;
    }

    protected override Expression VisitMember(MemberExpression node)
    {
    if (node.Expression == null || node.Expression.Type != typeof(TA))
    {
    return base.VisitMember(node);
    }
    Expression expression = this.Visit(node.Expression);
    if (expression.Type != typeof(TB))
    {
    throw new Exception("Whoops");
    }
    LambdaExpression lambdaExpression;
    if (this._mappings.TryGetValue(node.Member, out lambdaExpression))
    {
    return new SimpleExpressionReplacer(lambdaExpression.Parameters.Single(), expression).Visit(lambdaExpression.Body);
    }
    return Expression.Property(
    expression,
    node.Member.Name
    );
    }

    protected override Expression VisitLambda<T>(Expression<T> node)
    {
    return Expression.Lambda(
    this.Visit(node.Body),
    node.Parameters.Select(this.Visit).Cast<ParameterExpression>()
    );
    }

    public AToBConverter(Dictionary<MemberInfo, LambdaExpression> mappings)
    {
    this._mappings = mappings;
    }
    }

    sealed class SimpleExpressionReplacer : ExpressionVisitor
    {
    private readonly Expression _replacement;
    private readonly Expression _toFind;

    public override Expression Visit(Expression node)
    {
    return node == this._toFind ? this._replacement : base.Visit(node);
    }

    public SimpleExpressionReplacer(Expression toFind, Expression replacement)
    {
    this._toFind = toFind;
    this._replacement = replacement;
    }
    }

    class Program
    {
    private static Dictionary<MemberInfo, LambdaExpression> GetMappings()
    {
    var mappings = new Dictionary<MemberInfo, LambdaExpression>();
    var mapping = GetMappingFor(model => model.HasEvenId, customer => (customer.Id % 2) == 0);
    mappings.Add(mapping.Item1, mapping.Item2);
    mapping = GetMappingFor(model => model.FullName, customer => customer.FirstName + " " + customer.LastName);
    mappings.Add(mapping.Item1, mapping.Item2);
    return mappings;
    }

    private static Tuple<MemberInfo, LambdaExpression> GetMappingFor<TValue>(Expression<Func<CustomerModel, TValue>> fromExpression, Expression<Func<Customer, TValue>> toExpression)
    {
    return Tuple.Create(((MemberExpression)fromExpression.Body).Member, (LambdaExpression)toExpression);
    }

    static void Main()
    {
    Expression<Func<CustomerModel, bool>> source = model => model.HasEvenId && model.FullName == "John Smith";
    Expression<Func<Customer, bool>> desiredResult = model => (model.Id % 2) == 0 && (model.FirstName + " " + model.LastName) == "John Smith";
    Expression output = new AToBConverter<CustomerModel, Customer>(GetMappings()).Visit(source);
    Console.WriteLine("The two expressions do {0}match.", desiredResult.ToString() == output.ToString() ? null : "not ");
    Console.ReadLine();
    }
    }

    关于linq - 使用复杂的映射将表达式树从一种类型转换为另一种类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10570942/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com