值在AutoMapper的EnumerableMapper.SetElementValue中消失

时间:2014-04-03 12:02:13

标签: c# linq linq-to-sql automapper bindinglist

我使用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;
    }
}

ProductLine(子)域模型定义:

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));

ProductLine域到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));

1 个答案:

答案 0 :(得分:0)

我终于找到了解决问题的方法。我没有回答为什么会出现这种情况,但我现在确实有办法绕过它。

代码:

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 overwrites missing source property on list with child objects的答案,我可以根据自己的情况调整这些答案。

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

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