ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

c# – 使用Expression在另一个Expression中映射DTO类

2019-06-24 18:55:19  阅读:220  来源: 互联网

标签:c net entity-framework dto


我正在使用Entity Framework Code First并尝试从我的实体类映射到我的DTO类.但我很难搞清楚如何编写Selector.

在这个小例子中,我创建了一个Person类和一个Address类.

在DTO类中,我创建了一个Selector,它从我的Entity映射到我的DTO,但是不能在PersonDto.Selector中使用AddressDto.Selector吗?

public class Person
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public Address Address { get; set; }
    }

    public class Address
    {
        public int Id { get; set; }
        public string Street { get; set; }
    }

现在我正在尝试将其映射到DTO类.

    public class PersonDto
        {
            public static Expression<Func<Person, PersonDto>> Selector = 
            entity => new PersonDto
                {
                     Id = entity.Id,
                     Name = entity.Name,
                     Address = ??? AddressDTO.Selector
                };

            public int Id { get; set; }
            public string Name { get; set; }
            public AddressDto Address { get; set; }
        }

        public class AddressDto
        {
            public static Expression<Func<Address, AddressDto>> Selector = 
            entity => new AddressDto
                 {
                     Id = entity.Id,
                     Street = entity.Street
                 };

            public int Id { get; set; }
            public string Street { get; set; }
        }

我知道我可以在PersonDto.Selector中写这个

Address = new AddressDto
                     {
                         Id = entity.Address.Id,
                         Street = entity.Address.Street
                     };

但我正在寻找一种方法来重用AddressDto类中的Selector.保持代码清洁并在类之间分离责任.

解决方法:

所以,我们在这里需要几个辅助方法,但是一旦我们拥有它们,事情应该相当简单.

我们将从这个类开始,它可以用一个表达式替换另一个表达式的所有实例:

internal class ReplaceVisitor : ExpressionVisitor
{
    private readonly Expression from, to;
    public ReplaceVisitor(Expression from, Expression to)
    {
        this.from = from;
        this.to = to;
    }
    public override Expression Visit(Expression node)
    {
        return node == from ? to : base.Visit(node);
    }
}

然后是一个扩展方法,使调用更容易:

public static Expression Replace(this Expression expression,
    Expression searchEx, Expression replaceEx)
{
    return new ReplaceVisitor(searchEx, replaceEx).Visit(expression);
}

接下来我们将编写一个compose扩展方法.这将采用计算中间结果的lambda,然后是另一个基于中间结果计算最终结果的lambda,并返回一个新的lambda,它接受初始lambda返回的内容并返回最终lambda的输出.实际上它调用一个函数,然后在第一个函数的结果上调用另一个函数,但是使用表达式而不是方法.

public static Expression<Func<TFirstParam, TResult>>
    Compose<TFirstParam, TIntermediate, TResult>(
    this Expression<Func<TFirstParam, TIntermediate>> first,
    Expression<Func<TIntermediate, TResult>> second)
{
    var param = Expression.Parameter(typeof(TFirstParam), "param");

    var newFirst = first.Body.Replace(first.Parameters[0], param);
    var newSecond = second.Body.Replace(second.Parameters[0], newFirst);

    return Expression.Lambda<Func<TFirstParam, TResult>>(newSecond, param);
}

现在我们将创建一个Combine方法.这将是类似的,但略有不同.它将采用lambda来计算中间结果,并使用初始输入和中间输入来计算最终结果.它与Compose方法基本相同,但第二个函数也可以了解第一个参数:

public static Expression<Func<TFirstParam, TResult>>
    Combine<TFirstParam, TIntermediate, TResult>(
    this Expression<Func<TFirstParam, TIntermediate>> first,
    Expression<Func<TFirstParam, TIntermediate, TResult>> second)
{
    var param = Expression.Parameter(typeof(TFirstParam), "param");

    var newFirst = first.Body.Replace(first.Parameters[0], param);
    var newSecond = second.Body.Replace(second.Parameters[0], param)
        .Replace(second.Parameters[1], newFirst);

    return Expression.Lambda<Func<TFirstParam, TResult>>(newSecond, param);
}

好的,既然我们拥有了所有这些,我们就可以使用它了.我们要做的第一件事是创建一个静态构造函数;我们无法将所有必须内联到字段初始化程序中. (另一种选择是创建一个计算它的静态方法,并让初始化程序调用它.)

之后我们将创建一个表达人,并返回它的地址.这是你所拥有的表达中缺少的拼图之一.使用它,我们将使用AddressDto选择器组成该地址选择器,然后使用Combine.使用它我们有一个lambda,它接受一个Person和一个AddressDTO并返回一个PersonDTO.所以在那里我们基本上有你想要的东西,但有一个地址参数给我们分配给地址:

static PersonDto()
{
    Expression<Func<Person, Address>> addressSelector =
        person => person.Address;

    Selector = addressSelector.Compose(AddressDto.Selector)
            .Combine((entity, address) => new PersonDto
            {
                Id = entity.Id,
                Name = entity.Name,
                Address = address,
            });
}

标签:c,net,entity-framework,dto
来源: https://codeday.me/bug/20190624/1281120.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有