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

 

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
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);
       }
   }

 

 

测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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);
posted @   不夜橙  阅读(956)  评论(5编辑  收藏  举报
编辑推荐:
· .NET 原生驾驭 AI 新基建实战系列:向量数据库的应用与畅想
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
· 一次Java后端服务间歇性响应慢的问题排查记录
· dotnet 源代码生成器分析器入门
· ASP.NET Core 模型验证消息的本地化新姿势
阅读排行:
· ThreeJs-16智慧城市项目(重磅以及未来发展ai)
· .NET 原生驾驭 AI 新基建实战系列(一):向量数据库的应用与畅想
· Ai满嘴顺口溜,想考研?浪费我几个小时
· Browser-use 详细介绍&使用文档
· 软件产品开发中常见的10个问题及处理方法
点击右上角即可分享
微信分享提示