值在AutoMapper的EnumerableMapper.SetElementValue中消失

本文关键字:消失 SetElementValue EnumerableMapper AutoMapper 值在 | 更新日期: 2023-09-27 17:56:19

我正在使用AutoMapper将Linq-to-SQL对象映射到域模型。此 Linq-to-SQL 对象具有子对象。将 Linq-to-SQL 对象映射到其域模型后,所有值都是正确的。但是,将域模型映射回其 Linq-to-SQL 对应项后,所有子对象都会丢失其父 ID。

我已经将其缩小到AutoMapper的EnumerableMapper类中的SetElementValue()方法。子对象引用(在 SetElementValue() 中名为 mappedValue 的参数)会保留其父 id,直到它被添加到枚举对象中,在本例中是 IBindingList 的实现。添加到所述实现后,其父 ID 设置为 0。我比较了 Linq-to-SQL 对象和域模型对象中的所有值,并且除父 id 外,所有值都等于其原始状态。

我倾向于认为这与IBindingList的使用有关,在这里删除父ID有什么意义吗?我忽略了什么吗?我不确定您需要什么源代码来提供任何有用的建议,只需询问,您将收到您需要的任何东西。

活动(父)域模型定义:

public class Activity : IActivityEntity
{
    public int Id { get; set; }
    public string NameOrDescription { get; set; }
    public int ClientId;
    public int ActivityTypeId;
    public int PerformedByEmployeeId;
    public bool IsBillable;
    public DateTime PerformedDate { get; set; }
    public DateTime StartTime { get; set; }
    public DateTime StopTime { get; set; }
    public string Description { get; set; }
    public int ProjectId;
    public int WorkOrderId;
    public IList<ProductLine> ProductLines;
    public Activity()
    {
        this.ProductLines = new List<ProductLine>();
    }
    public Activity(ActivityType activityType, int clientId, int employeeId, int workOrderId, DateTime startTime, DateTime stopTime, DateTime performedDate, string description)
    {
        this.ClientId = clientId;
        this.ActivityTypeId = activityType.Id;
        this.PerformedByEmployeeId = employeeId;
        this.Description = description ?? "";
        this.IsBillable = activityType.IsBillable;
        this.StartTime = startTime;
        this.StopTime = stopTime;
        this.PerformedDate = performedDate;
        this.WorkOrderId = workOrderId;
    }
}

产品线(子)域模型定义:

public class ProductLine : IEntity
{
    public int Id;
    public int ClientId;
    public int ProductId;
    public int ProductGroupId;
    public string ProductNumber;
    public int SupplierId;
    public string Name;
    public int ActivityId;
    public int WorkOrderId;
    public float Amount;
    public decimal InPriceWithoutVAT;
    public decimal OutPriceWithoutVAT;
    public bool IsBillable;
    public double? DiscountPercentage;
    public string Denomination;
    public bool CreatedBySystem;
    public bool StructureProductLine;
    public int SellerEmployeeId;
    public int ConsultantEmployeeId;
    public ProductLine()
    {
    }
}

活动域到 DTO 规则:

Mapper.CreateMap<Activity, D.Activity>()
            .ForMember(dto => dto.ActivityID, options => options.MapFrom(activity => activity.Id))
            .ForMember(dto => dto.ClientID, options => options.MapFrom(activity => activity.ClientId))
            .ForMember(dto => dto.ActivityTypeID, options => options.MapFrom(activity => activity.ActivityTypeId))
            .ForMember(dto => dto.Description, options => options.MapFrom(activity => activity.Description))
            .ForMember(dto => dto.StartTime, options => options.MapFrom(activity => activity.StartTime))
            .ForMember(dto => dto.StopTime, options => options.MapFrom(activity => activity.StopTime))
            .ForMember(dto => dto.IsBillable, options => options.MapFrom(activity => activity.IsBillable))
            .ForMember(dto => dto.WorkOrderID, options => options.MapFrom(activity => activity.WorkOrderId))
            .ForMember(dto => dto.PerformedByEmployeeID, options => options.MapFrom(activity => activity.PerformedByEmployeeId));

产品线域到 DTO 规则:

Mapper.CreateMap<ProductLine, D.ProductLine>()
            .ForMember(dto => dto.ProductLineID, options => options.MapFrom(productLine => productLine.Id))
            .ForMember(dto => dto.ActivityID, options => options.MapFrom(productLine => productLine.ActivityId))
            .ForMember(dto => dto.Amount, options => options.MapFrom(productLine => productLine.Amount))
            .ForMember(dto => dto.Billable, options => options.MapFrom(productLine => productLine.IsBillable))
            .ForMember(dto => dto.ClientID, options => options.MapFrom(productLine => productLine.ClientId))
            .ForMember(dto => dto.Name, options => options.MapFrom(productLine => productLine.Name))
            .ForMember(dto => dto.OutPriceWithoutWAT, options => options.MapFrom(productLine => productLine.OutPriceWithoutVAT))
            .ForMember(dto => dto.ProductGroupID, options => options.MapFrom(productLine => productLine.ProductGroupId))
            .ForMember(dto => dto.ProductID, options => options.MapFrom(productLine => productLine.ProductId))
            .ForMember(dto => dto.ProductNumber, options => options.MapFrom(productLine => productLine.ProductNumber))
            .ForMember(dto => dto.StructureProductLine, options => options.MapFrom(productLine => productLine.StructureProductLine))
            .ForMember(dto => dto.SupplierID, options => options.MapFrom(productLine => productLine.SupplierId))
            .ForMember(dto => dto.InPriceWithoutWAT, options => options.MapFrom(productLine => productLine.InPriceWithoutVAT))
            .ForMember(dto => dto.Denomination, options => options.MapFrom(productLine => productLine.Denomination))
            .ForMember(dto => dto.SoldByEmployeeID, options => options.MapFrom(productLine => productLine.SellerEmployeeId))
            .ForMember(dto => dto.ConsultantEmployeeID, options => options.MapFrom(productLine => productLine.ConsultantEmployeeId))
            .ForMember(dto => dto.WorkOrderID, options => options.MapFrom(productLine => productLine.WorkOrderId));

值在AutoMapper的EnumerableMapper.SetElementValue中消失

我终于找到了解决烦恼的方法。我不知道为什么会发生这种行为,但我现在确实有办法规避它。

法典:

Mapper.CreateMap<Activity, D.Activity>()
            .ForMember(dto => dto.ActivityID, options => options.MapFrom(activity => activity.Id))
            .ForMember(dto => dto.ClientID, options => options.MapFrom(activity => activity.ClientId))
            .ForMember(dto => dto.ActivityTypeID, options => options.MapFrom(activity => activity.ActivityTypeId))
            .ForMember(dto => dto.Description, options => options.MapFrom(activity => activity.Description))
            .ForMember(dto => dto.StartTime, options => options.MapFrom(activity => activity.StartTime))
            .ForMember(dto => dto.StopTime, options => options.MapFrom(activity => activity.StopTime))
            .ForMember(dto => dto.IsBillable, options => options.MapFrom(activity => activity.IsBillable))
            .ForMember(dto => dto.WorkOrderID, options => options.MapFrom(activity => activity.WorkOrderId))
            .ForMember(dto => dto.PerformedByEmployeeID, options => options.MapFrom(activity => activity.PerformedByEmployeeId))
            .ForMember(dto => dto.ProductLines, options => options.Ignore())
            .AfterMap((src, dest) =>
                {
                    foreach (var productLine in src.ProductLines)
                    {
                        dest.ProductLines.Add(Mapper.Map<D.ProductLine>(productLine));
                    }
                });

解释

D.ProductLine 的字段 ActivityID 在以前的 AutoMapper 规则中始终设置为零,原因我无法解释,但前提是 D.ProductLine 是 D.Activity 或任何其他对象的子对象。如果我只映射D.ProductLine本身,ActivityID是正确的。经过 8 个小时的抨击和研究,我发现 Merenzo 的答案在 Automapper 用子对象覆盖列表中缺少的源属性,我可以调整这些子对象来帮助我解决我的情况。

通过告诉AutoMapper忽略Activity.ProductLines,我可以像Merenzo一样,在所有其他映射完成后使用AfterMap()进行到D.ProductLine的映射。因此,映射D.ProductLine而没有AutoMapper"意识到"它是D.Activity的子对象,拒绝将D.ProductLine.ActivityID设置为零。

如前所述,我无法通过AutoMapper解释这种行为,但是我现在可以根据需要绕过它。如果有人对此行为有更好的解决方案或解释,请不要犹豫,发布:)