AutoMapper运行时通过IMappingOperationOptions映射控制

目录

介绍

背景

使用代码

结论

注意

兴趣点


介绍

AutoMapper是一个很好的工具,可以轻松地在两个类之间进行映射。但是,如果映射在NHibernate实体和DTO(数据传输对象)之间,则可能会变得很危险。使用NHibernate的延迟加载功能,这很容易导致不需要的数据库选择。AutoMapper有一些很好的特性,通过Queryable Extensions让开发人员可以控制在运行时应该和不应该映射的内容。

但是还有一个被严重低估的特性,隐藏在它的ResolutionContext->Options中,它只是在文档中简单提到:Passing in key-value to Mapper

我说的是一个名为Items的属性的小宝石,它只是一个IDictionary<string, object>

有了这个,您可以直接控制要从数据库中接收哪些数据,我将通过一个小示例向您展示。

背景

一方面拥有具有引用和列表的实体,另一方面拥有DTO,您可能会发现,AutoMapper将始终尝试尽可能映射所有内容。因此,您要么必须为不同的用例创建不同的DTO,要么只需使用NHibernates延迟加载的魔力并通过标志直接控制前端可以直接传递远程调用。

让我们看看这是如何工作的!

使用代码

考虑两个类的这个简单示例:CustomerOrders
(这只是一个基本示例,不要与真实的公司应用程序混淆。)

一方面,你得到了这些NHibernate实体:

public class Customer
{
    public virtual long Id { get; set; }
 
    public virtual string Name { get; set; }
 
    public virtual IList<Order> Orders { get; set; }
}
 
public class Order
{
    public virtual long Id { get; set; }
 
    public virtual string ProductNumber { get; set; }
 
    public virtual int Amount { get; set; }
}

以下是DTO

public class CustomerDto
{
    public long Id { get; set; }
 
    public string Name { get; set; }
 
    public IList<OrderDto> Orders { get; set; }
}
 
public class OrderDto
{
    public long Id { get; set; }
 
    public string ProductNumber { get; set; }
 
    public int Amount { get; set; }
}

现在,假设您有两个用例:

  • 仅检索用户
  • 检索用户及其订单

为此,我们需要为IMappingOperationOptions扩展类。

此扩展将从Options->Items存储和检索标志。

public static class OperationOptionExtensions
{
    // List of different keys for the Items Dictionary
 
    private const string ShouldIncludeOrdersForCustomerKey = "ShouldIncludeOrdersForCustomer";
 
    // ----
    
    /// <summary>
    /// Retreives a bool value from the Items Dictionary by key
    /// </summary>
    private static bool GetBoolValue(IMappingOperationOptions options, string key)
    {
        if (options.Items.ContainsKey(key) && options.Items[key] is bool value)
        {
            return value;
        }
 
        return false;
    }
 
    /// <summary>
    /// Saves the bool value, whenever or not the mapping should include
    /// the Orders List for Customer
    /// </summary>
    public static void IncludeOrdersForCustomer(
        this IMappingOperationOptions options,
        bool include = true)
    {
        options.Items[ShouldIncludeOrdersForCustomerKey] = include;
    }
 
    /// <summary>
    /// Mapping in Profile requests, whenever or not it should include
    /// the Orders List for Customer
    /// </summary>
    public static bool ShouldIncludeOrdersForCustomer(this IMappingOperationOptions options)
    {
        return GetBoolValue(options, ShouldIncludeOrdersForCustomerKey);
    }
}

现在我们可以配置我们的映射配置文件,告诉AutoMapper只映射Orders是否使用PreCondition操作设置了标志:

public class AutoMapperConfig : Profile
{
    public AutoMapperConfig()
    {
        CreateMap<Customer, CustomerDto>()
 
            // The PreCondition retreives the stored value
            // from the Items Dictionary inside the mapping options
            .ForMember(
                customer => customer.Orders,
                config => config.PreCondition(
                    context => context.Options.ShouldIncludeOrdersForCustomer()));
 
        CreateMap<Order, OrderDto>();
    }
}

该条件默认返回false,因此只有在运行时启用该选项时才会映射Order

考虑这个使用NHibernate的数据库访问层的简化示例:

public class DBAccess
{
    // Assume Dependency-Injection of NHibernate Session here
    public ISession Session { get; set; }
 
    private IMapper Mapper { get; }
 
    public DBAccess()
    {
        // Profile and configuration
        var config = new MapperConfiguration(cfg =>
        {
            cfg.AddProfile<AutoMapperConfig>();
        });
 
        // Also typically by Dependency-Injection
        Mapper = config.CreateMapper();
    }
 
    /// <summary>
    /// Data-Access method: includeOrders will be requested by the front-end
    /// </summary>
    public CustomerDto GetCustomerById(long customerId, bool includeOrders)
    {
        // Retreive the Customer from database
        var customer = Session.Get<Customer>(customerId);
 
        // We directly inject the clients request for the Orders
        // into this mapping operation option
        return Mapper.Map<CustomerDto>(customer, options =>
        {
            options.IncludeOrdersForCustomer(includeOrders);
        });
    }
}

如果includeOrders设置为trueAutoMapper将通过触发NHibernates延迟加载来映射Orders

如果设置为falseAutoMapper则不会映射Orders并且DTO内的Order列表保持为空。NHibernate不会延迟加载Orders

当然,这可以通过任何其他属性来完成,并且在String-ObjectDictionary中存储任何东西的可能性是无穷无尽的。在这种情况下,它们只是更好地控制应该映射的内容的标志。

结论

使用AutoMapperOperation-Options可以让您从前到后直接控制运行时映射,从而减少类和更短的代码。

注意

我知道您也可以简单地通过代码检查includeOrders,执行另一个查询Orders并手动填写它们。但这只是提高认识的一个基本示例。我确信其他开发人员可以为很多其他的东西使用Dictionary来控制和操纵AutoMapper的行为。

兴趣点

老实说,当我第一次偶然发现这个简单的Dictionary时,它真的让我大吃一惊。

我首先想到的是这个扩展,它可以更好地控制AutoMappers的行为,而不必维护太多不同的DTO。我希望这会引起其他开发人员的注意AutoMapper,他们不喜欢它或改用其他映射器。

控制就是一切!

https://www.codeproject.com/Tips/5320490/AutoMapper-Runtime-Mapping-Control-via

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
AutoMapper是一个用于对象映射的开源库。它可以帮助简化对象之间的转换过程,减少手动编写重复的代码。通过配置映射规则,AutoMapper可以自动将一个对象的属性值复制到另一个对象中对应的属性上,而不需要手动逐个属性进行赋值。 使用AutoMapper,你可以定义映射规则,包括源类型和目标类型以及它们之间的属性映射关系。一旦配置好映射规则,你可以使用简单的API将源对象映射到目标对象上。 以下是一个使用AutoMapper的示例: ```csharp // 定义源类型和目标类型 public class SourceObject { public string Name { get; set; } public int Age { get; set; } } public class DestinationObject { public string Name { get; set; } public int Age { get; set; } } // 配置映射规则 var config = new MapperConfiguration(cfg => { cfg.CreateMap<SourceObject, DestinationObject>(); }); // 创建映射器 var mapper = config.CreateMapper(); // 创建源对象 var source = new SourceObject { Name = "John", Age = 30 }; // 使用映射器进行对象映射 var destination = mapper.Map<SourceObject, DestinationObject>(source); // 输出目标对象属性值 Console.WriteLine(destination.Name); // 输出:John Console.WriteLine(destination.Age); // 输出:30 ``` 通过使用AutoMapper,你可以简化对象之间的映射过程,提高开发效率。它支持各种复杂的映射场景,并且可以通过自定义转换器来处理更复杂的映射逻辑。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值