AutoMapper:映射 ImmutableHashSet 的问题

AutoMapper: Issues mapping an ImmutableHashSet

我正在尝试使用 AutoMapper.[=52= MapReverseMap ImmutableHashSet 属性 到 ICollection ]

Automapper 成功地将 ImmutableHashSet 属性 映射到 ICollection,但未能将 ICollection 映射回 ImmutableHashSet

这是最小的可重现示例:

考虑我有 OrderOrderItem class 如下:

public class Order
{
    private HashSet<OrderItem> _orderItems;

    public Order()
    {
        _orderItems = new HashSet<OrderItem>();
    }

    public ImmutableHashSet<OrderItem> OrderItems
    {
        get => _orderItems.ToImmutableHashSet();
        private set => _orderItems = value.ToHashSet();
    }

    public void AddOrderItem(OrderItem orderItem)
    {
        _orderItems.Add(orderItem);
    }

    public void RemoveOrderItem(OrderItem orderItem)
    {
        _orderItems.Add(orderItem);
    }
}

public class OrderItem
{
    public OrderItem(int orderId, string orderName)
    {
        OrderId = orderId;
        OrderName = orderName;
    }

    public int OrderId { get; private set; }


    public string OrderName { get; private set; }
}

OrderOrderItem classes需要映射到下面的OrderDto和classes

public class OrderDto
{
    public ICollection<OrderItem> OrderItems { get; set; }
}

public class OrderItemDto
{

    public int OrderId { get; set; }


    public string OrderName { get; set; }
}

下面的 OrderProfile class 定义了将 Order 映射到 OrderDto 的 Automapper 配置文件,反之亦然。

public class OrderProfile : Profile
{
    public OrderProfile()
    {
        CreateMap<Order, OrderDto>()
            .ReverseMap();
        CreateMap<OrderItem, OrderItemDto>()
            .ReverseMap();
    }
}

public class OrderItemDto
{

    public int OrderId { get; set; }


    public string OrderName { get; set; }
}

映射和反向映射 OrderOrderDto class 的代码:

private static void Map()
{
    var mapper = new MapperConfiguration(cfg =>
    {
        cfg.AddProfile(new OrderProfile());
    }).CreateMapper();

    var order = new Order();
    order.AddOrderItem(new OrderItem(1, "Laptop"));
    order.AddOrderItem(new OrderItem(2, "Keyboard"));

    // This code maps correctly
    var orderDto = mapper.Map<OrderDto>(order);

    // This is where I get an exception
    var orderMappedBack = mapper.Map<Order>(orderDto);
}

OrderDto 映射 Order object 时,出现以下异常:

System.ArgumentException: System.Collections.Immutable.ImmutableHashSet`1[ReadOnlyCollectionDemo.OrderItem]
needs to have a constructor with 0 args or only optional args.
(Parameter 'type') at lambda_method(Closure , OrderDto , Order , ResolutionContext )

非常感谢任何有助于解决此问题的指示。

更新

我以某种方式通过自定义Converter让它工作。但我真的不知道它是如何工作的。我更新了我的映射器配置如下:

 var mapper = new MapperConfiguration(cfg =>
        {
            cfg.AddProfile(new OrderProfile());
            cfg.CreateMap(typeof(ICollection<>), typeof(ImmutableHashSet<>)).ConvertUsing(typeof(HashMapConverter<,>));
        }).CreateMapper();

我的HashMapConverterclass:

public class HashMapConverter<TCollection, TImmutableHashSet> 
        : ITypeConverter<ICollection<TCollection>, ImmutableHashSet< TImmutableHashSet>>
    {
        public ImmutableHashSet< TImmutableHashSet> Convert(
            ICollection<TCollection> source,
            ImmutableHashSet< TImmutableHashSet> destination,
            ResolutionContext context)
        {
            return ImmutableHashSet<TImmutableHashSet>.Empty;
        }
    }

如您所见,我只是返回了一个空的 ImmutableHashSet,然而,令我惊讶的是,OrderDto 现在已成功映射回 Order,并且具有正确的 OrderItems Count。我原以为 Count 为 0,因为我返回的是一个空的 HashSet。我怀疑它正在工作,因为 OrderItemOrderItemDto 也通过 AutoMapper.

映射

我想证实我的假设并知道这是否是一个正确的方法。

在我的类似示例中,我没有得到期望值,而是一个空集合,因此您最好使用

完成转换函数
public class HashMapConverter<TCollection, TImmutableHashSet>
: ITypeConverter<ICollection<TCollection>, ImmutableHashSet<TImmutableHashSet>>
{
    public ImmutableHashSet<TImmutableHashSet> Convert(
        ICollection<TCollection> source,
        ImmutableHashSet<TImmutableHashSet> destination,
        ResolutionContext context)
    {
        var hs =new HashSet<TCollection>(source);
        return ((IEnumerable<TImmutableHashSet>)hs).ToImmutableHashSet<TImmutableHashSet>();
        //return ImmutableHashSet<TImmutableHashSet>.Empty;
    }
}

而不是返回空;

事实证明,将 ImmutableHashSet 映射到集合并不像看起来那么简单。然而,这让我意识到也许我没有解决正确的问题。我只想确保我的 OrderItem HashSet 不能在 Order class 之外被修改。我可以通过返回 IReadOnlyCollection 轻松实现这一点。

这是我更新的 Order class:

public class Order
{
    private HashSet<OrderItem> _orderItems;

    public Order()
    {
        _orderItems = new HashSet<OrderItem>();
    }

    public IReadOnlyCollection<OrderItem> OrderItems
    {
        get => _orderItems.ToImmutableHashSet();
        private set => _orderItems = value.ToHashSet();
    }

    public void AddOrderItem(OrderItem orderItem)
    {
        _orderItems.Add(orderItem);
    }

    public void RemoveOrderItem(OrderItem orderItem)
    {
        _orderItems.Add(orderItem);
    }
}

IReadOnlyCollection 不仅帮助我解决了 Automapper 问题,而且除此之外,它没有公开 Add 方法。因此,用户不会意外地在 Order class.

之外调用 order.OrderItems.Add(orderItem) 方法