映射表达式表达式< Func< UserVM,object>>到表达式< Func< UserVM,object>> [英] Mapping expressions Expression<Func<UserVM, object>> to Expression<Func<UserVM, object>>

查看:92
本文介绍了映射表达式表达式< Func< UserVM,object>>到表达式< Func< UserVM,object>>的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在架构中传播实体框架包含属性。

1.从服务层开始,其中包含属性作为参数

I would like to propagate entity framework include properties across architecture.
1. Starting at the service layer where these include properties come as an argument

IEnumerable<UserVM> GetUsers(user => user.Classes);





2.方法getUsers必须将此表达式从ViewModel转换为Model



2. The method getUsers must translate this expressions from ViewModel to Model

IEnumerable<UserVM> GetUser(Expression<Func<UserVm, object>> includePropertyVM)
{
   Expression<Func<User, object>> includeProperty Mapper.Map<Expression<Func<User, object>>>(includePropertyVM);

  Repository.GetUsers(includeProperty);

}





但它不起作用!

Autommaper无法处理它。你有这方面的经验吗?我想将这个lamda表达式互相翻译。



But it does not work!
Autommaper can not handle it. Have you any experience with it? I want to translate this lamda expressions to each other.

推荐答案

我不知道是否可以使用AutoMapper完成。但这是你自己可以做到的,不包括Repository-call。有一个通用的非泛型版本的映射方法;我认为你应该可以使用通用的那个。

I don't know if it can be done with AutoMapper. But this is how you could do it yourself, not including the Repository-call. There's a generic and non-generic version of the mapping-method; I think you should be able to use the generic one.
using System;
using System.Linq.Expressions;

namespace MemberMapping
{
    class User
    {
        public string Name { get; set; }
    }

    class UserVM
    {
        public string Name { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            User testUser = new User() { Name = "Paul" };

            Expression<Func<User, object>> genericMapping = MapMemberLambda<UserVM, User>(user => user.Name);
            Expression<Func<User, object>> nonGenericMapping = MapUserMemberLambda(user => user.Name);

            string testGenericMapping = (string)genericMapping.Compile().Invoke(testUser);
            string testNonGenericMapping = (string)nonGenericMapping.Compile().Invoke(testUser);

            Console.WriteLine(testGenericMapping); // writes "Paul"
            Console.WriteLine(testNonGenericMapping); // writes "Paul"
        }

        static Expression<Func<TTarget, object>> MapMemberLambda<TSource, TTarget>(Expression<Func<TSource, object>> includePropertyVM)
        {
            ParameterExpression objectParam = Expression.Parameter(typeof(TTarget), "x");

            Expression memberAccess = Expression.PropertyOrField(objectParam, ((MemberExpression)includePropertyVM.Body).Member.Name);

            return Expression.Lambda<Func<TTarget, object>>(memberAccess, objectParam);
        }

        static Expression<Func<User, object>> MapUserMemberLambda(Expression<Func<UserVM, object>> lambda)
        {
            ParameterExpression objectParam = Expression.Parameter(typeof(User), "x");

            Expression memberAccess = Expression.PropertyOrField(objectParam, ((MemberExpression)lambda.Body).Member.Name);

            return Expression.Lambda<Func<User, object>>(memberAccess, objectParam);
        }
    }
}





编辑:映射方法期望成员名称的完全匹配。如果您依靠AutoMappers将用户等成员名称模糊匹配到UserName的能力,那么您必须自己完成此操作。您必须从((MemberExpression)lambda.Body).Member.Name 中获取source-member-name,找到目标成员的最佳匹配成员名称type(参见 typeof(TTarget).GetMembers())并将该成员名称放在((MemberExpression)lambda.Body).Member.Name 现在。



编辑2:按照评论的要求:允许嵌套成员访问的映射,如 user  =>  user.Foo.Bar.Baz



The mapping methods expect an exact match of the member names. If you counted on AutoMappers ability to "fuzzy-match" member names like "User" to "UserName" you'll have to do this on your own here. You would have to take the source-member-name from ((MemberExpression)lambda.Body).Member.Name, find the best matching member name of the members of the target type (see typeof(TTarget).GetMembers()) and put that member name where ((MemberExpression)lambda.Body).Member.Name is now.

Edit 2: As requested per comment: Allowing the mapping of nested member access like user => user.Foo.Bar.Baz:

using System;
using System.Collections.Generic;
using System.Linq.Expressions;

namespace MemberMapping
{
    class Foo
    {
        public string Bar { get; set; }
    }

    class Address
    {
        public string Street { get; set; }
        public Foo Foo { get; set; }
    }

    class User
    {
        public string Name { get; set; }
        public Address Address { get; set; }
    }

    class FooVM
    {
        public string Bar { get; set; }
    }

    class AddressVM
    {
        public string Street { get; set; }
        public FooVM Foo { get; set; }
    }

    class UserVM
    {
        public string Name { get; set; }
        public AddressVM Address { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            User testUser = new User()
            {
                Name = "Paul",
                Address = new Address()
                {
                    Street = "Freeway",
                    Foo = new Foo() { Bar = "Baz" }
                }
            };

            Expression<Func<User, object>> nameMapping = MapMemberLambda<UserVM, User>(user => user.Name);
            Expression<Func<User, object>> streetMapping = MapMemberLambda<UserVM, User>(user => user.Address.Street);
            Expression<Func<User, object>> barMapping = MapMemberLambda<UserVM, User>(user => user.Address.Foo.Bar);

            string nameMappingResult = (string)nameMapping.Compile().Invoke(testUser);
            string streetMappingResult = (string)streetMapping.Compile().Invoke(testUser);
            string barMappingResult = (string)barMapping.Compile().Invoke(testUser);

            Console.WriteLine(nameMappingResult);   // writes "Paul"
            Console.WriteLine(streetMappingResult); // writes "Freeway"
            Console.WriteLine(barMappingResult);    // writes "Baz"
            Console.ReadLine();
        }

        static Expression<Func<TTarget, object>> MapMemberLambda<TSource, TTarget>(Expression<Func<TSource, object>> sourceLambdaExpr)
        {
            // We need to build the mapped expression in the reverse order we
            // can traverse the source expression. So we use a stack to push
            // the names of the members that are being accessed onto it and
            // then pop them off the stack again while building the mapped
            // expression.

            Stack<string> memberNames = new Stack<string>();

            MemberExpression currentMemberExpr = (MemberExpression)sourceLambdaExpr.Body;
            while (true)
            {
                memberNames.Push(currentMemberExpr.Member.Name);
                if (currentMemberExpr.Expression is ParameterExpression)
                    break;
                currentMemberExpr = (MemberExpression)currentMemberExpr.Expression;
            }

            ParameterExpression objectParamExpr = Expression.Parameter(typeof(TTarget), "x");
            Expression currentMappedExpr = objectParamExpr;
            while (memberNames.Count > 0)
            {
                currentMappedExpr = Expression.PropertyOrField(currentMappedExpr, memberNames.Pop());
            }

            return Expression.Lambda<Func<TTarget, object>>(currentMappedExpr, objectParamExpr);
        }
    }
}


这篇关于映射表达式表达式&lt; Func&lt; UserVM,object&gt;&gt;到表达式&lt; Func&lt; UserVM,object&gt;&gt;的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆