zoukankan      html  css  js  c++  java
  • AutoMapper映射ExpressionTree

    问题描述

    项目中使用AutoMapper进行VO&DTO&Entity的互相映射,但是默认Map方法不支持Expression的转换。如

    Expression<Func<Entity,bool>> fun = _ => _.A == "A";

    希望转换成

    Expression<Func<Dto,bool>> fun = _ => _.A == "A";

    似乎解决方案就是解析ExpressionTree并映射替换节点。正好找到了人家的提问和解决方案

    http://stackoverflow.com/questions/7424501/automapper-for-funcs-between-selector-types

    改造一下支持泛型,代码如下:

     public static class FunctionCompositionExtensions
        {
            private static ConcurrentDictionary<Tuple<Type, Type>, Tuple<MethodInfo, Expression>> dictionary = new ConcurrentDictionary<Tuple<Type, Type>, Tuple<MethodInfo, Expression>>();
            private static MethodInfo method = typeof(FunctionCompositionExtensions).GetMethod("Compose", BindingFlags.NonPublic | BindingFlags.Static);
    
            public static Expression<Func<D, bool>> MapExpression<S, D>(this Expression<Func<S, bool>> selector)
            {
                var bulidMethod = dictionary.GetOrAdd(new Tuple<Type, Type>(typeof(S), typeof(D)), _ =>
                {
                    var expression = Mapper.Engine.CreateMapExpression<D, S>();
                    return new Tuple<MethodInfo, Expression>(method.MakeGenericMethod(typeof(D), typeof(bool), typeof(S)), expression);
                });
                return bulidMethod.Item1.Invoke(null, new[] { selector, bulidMethod.Item2 }) as Expression<Func<D, bool>>; 
    
            }
    
             static Expression<Func<X, Y>> Compose<X, Y, Z>(this Expression<Func<Z, Y>> outer, Expression<Func<X, Z>> inner)
            {
                return Expression.Lambda<Func<X, Y>>(
                    ParameterReplacer.Replace(outer.Body, outer.Parameters[0], inner.Body),
                    inner.Parameters[0]);
            }
    
             static Expression<Predicate<X>> ComposePredicate<X, Z>(this Expression<Predicate<Z>> outer, Expression<Func<X, Z>> inner)
            {
                return Expression.Lambda<Predicate<X>>(
                    ParameterReplacer.Replace(outer.Body, outer.Parameters[0], inner.Body),
                    inner.Parameters[0]);
            }
        }
    
        class ParameterReplacer : ExpressionVisitor
        {
            private ParameterExpression _parameter;
            private Expression _replacement;
    
            private ParameterReplacer(ParameterExpression parameter, Expression replacement)
            {
                 _parameter = parameter;
                _replacement = replacement;
            }
    
            public static Expression Replace(Expression expression, ParameterExpression parameter, Expression replacement)
            {
                return new ParameterReplacer(parameter, replacement).Visit(expression);
            }
    
            protected override Expression VisitParameter(ParameterExpression parameter)
            {
                if (parameter == _parameter)
                {
                    return _replacement;
                }
                return base.VisitParameter(parameter);
            }
        }

    测试

    public class Entity
    {
        public string A { get; set; }
    }
    
    public class Dto
    {
        public string A { get; set; }
    }
    
        
    Mapper.CreateMap<Entity, Dto>();
    Mapper.CreateMap<Dto, Entity>();
    
    
    var list = new List<Dto>()
    {
      new Dto() {A = "A"},
      new Dto() {A = "B"},
      new Dto() {A = "C"},
      new Dto() {A = "D"},
      new Dto() {A = "E"},
    };
    
    //Predicate<Entity> fun = _ => _.A =="A";
    Expression<Func<Entity,bool>> funEntity = _ => _.A == "A";
    
    var query = list.Where(funEntity.MapExpression<Entity, Dto>().Compile());
    Assert.True(query.Count() == 1);
    
    Expression<Func<Entity, bool>> funEntity2 = _ => _.A == "F";
    var query2 = list.Where(funEntity2.MapExpression<Entity, Dto>().Compile());
    Assert.True(query2.Count() == 0);
  • 相关阅读:
    postgres column reference "id" is ambiguous
    网络 内网穿透frp
    odoo12 支付宝在线支付
    odoo 账号登录不上,重置密码也不管用
    odoo 取消保存提示
    聊聊redis分布式锁的8大坑 转载
    用 Keepalived+HAProxy 实现高可用负载均衡的配置方法 转载
    Nginx+keepalived 实现高可用,常用防盗链及动静分离配置 转载
    Git 实用技巧记录 转载:https://mp.weixin.qq.com/s/o6FvGfiG9b57xTeXlBzzQQ
    5 个冷门但非常实用的 Kubectl 使用技巧,99% 的人都不知道 https://mp.weixin.qq.com/s/h4_KRmsVSnlqCmIJh0altA
  • 原文地址:https://www.cnblogs.com/miku/p/4367302.html
Copyright © 2011-2022 走看看