使用自我多对多的关系将映射器Dto转换为实体

时间:2018-02-27 22:25:01

标签: asp.net .net entity-framework automapper

我有一个包含4个类的项目:Direction,Area,Section和Local。方向有很多区域,区域有很多区域,区域有很多当地人。本地有正面的本地人和负面的本地人,因此本地实体将有自己的多对多关系。我使用Automapper将LocalDto转换为Local,但是当我尝试使用positives locals和/或negatives locals更新此实体时,系统会生成此异常:

  

操作失败:无法更改关系,因为一个或多个外键属性不可为空。当对关系进行更改时,相关的外键属性将设置为空值。如果外键不支持空值,则必须定义新关系,必须为外键属性分配另一个非空值,或者必须删除不相关的对象。

所以,它们是我的实体的mapper类:

******* ******* DirectionMapper

public static class DirectionMappers
{
    public static void SettingMappingDirectionToDirectionDto()
    {
        Mapper.CreateMap<Direction, DirectionDto>()
        .ForMember(directionDto => directionDto.AreasDtosList,
            mc => mc.MapFrom(direction => direction.AreasCollection));

    }

    public static void SettingMappingDirectionDtoToDirection()
    {
        Mapper.CreateMap<DirectionDto, Direction>()
        .ForMember(direction => direction.AreasCollection,
             mc => mc.MapFrom(directionDto => directionDto.AreasDtosList));
    }

    public static void SettingMappingDirectionToString()
    {
        Mapper.CreateMap<Direction, string>().ConvertUsing(direction => direction.Name ?? string.Empty);
    }
}

******** AreaMapper **********

  public class AreaMappers
{
    public static void SettingMappingAreaToAreaDto()
    {
        Mapper.CreateMap<Area, AreaDto>()
            .ForMember(areaDto => areaDto.SectionsDtosList, mc => mc.MapFrom(area => area.SectionsCollection))
            .ForMember(areaDto => areaDto.DirectionDto, mc => mc.MapFrom(area => area.Direction));

    }
    public static void SettingMappingAreaDtoToArea()
    {
        Mapper.CreateMap<AreaDto, Area>()
            .ForMember(area => area.SectionsCollection, mc => mc.MapFrom(areaDto => areaDto.SectionsDtosList))
            .ForMember(area => area.Direction,mc=> mc.MapFrom(areaDto=> areaDto.DirectionDto));

    }

    public static void SettingMappingAreaToString()
    {
        Mapper.CreateMap<Area, string>().ConvertUsing(area => area.Name ?? string.Empty);
    }
}

****** SectionMapper *******************

public class SectionMappers
{
    public static void SettingMappingSectionToSectionDto()
    {
        Mapper.CreateMap<Section, SectionDto>()
            .ForMember(sectionDto => sectionDto.LocalsDtosList, mc => mc.MapFrom(section => section.LocalsCollection))
            .ForMember(sectionDto => sectionDto.AreaDto, mc => mc.MapFrom(section => section.Area));
    }
    public static void SettingMappingSectionDtoToSection()
    {
        Mapper.CreateMap<SectionDto, Section>()
            .ForMember(section => section.LocalsCollection,
                mc => mc.MapFrom(sectionDto => sectionDto.LocalsDtosList))
            .ForMember(section => section.Area, mc => mc.MapFrom(sectionDto => sectionDto.AreaDto));

    }

    public static void SettingMappingSectionToString()
    {
        Mapper.CreateMap<Section, string>().ConvertUsing(section => section.Name ?? string.Empty);
    }
}

****** LocalMapper(主菜)******

public static class LocalMappers
{
    public static void SettingMappingLocalToLocalDto()
    {
        Mapper.CreateMap<Local, LocalDto>()
                        .ForMember(localDto => localDto.PositivesLocalsDtos,
                                   mc => mc.MapFrom(local => local.PositivesLocals)
                                   )
                        .ForMember(localDto => localDto.NegativesLocalsDtos,
                                   mc => mc.MapFrom(local => local.NegativesLocals)
                                   )

             .ForMember(localDto => localDto.SectionDto, mc => mc.MapFrom(local => local.Section));


    }
    public static void SettingMappingLocalDtoToLocal()
    {
        Mapper.CreateMap<LocalDto, Local>()
            .ForMember(local => local.PositivesLocals,
                mc => mc.MapFrom(localDto => localDto.PositivesLocalsDtos)
            )
            .ForMember(local => local.NegativesLocals,
                mc => mc.MapFrom(localDto => localDto.NegativesLocalsDtos)
            )

            .ForMember(local => local.Section, mc => mc.MapFrom(localDto => localDto.SectionDto));
    }

    public static void SettingMappingLocalToString()
    {
        Mapper.CreateMap<Local, string>().ConvertUsing(local => local.Number ?? string.Empty);
    }

}

嗯,这是本地更新的服务方法:

 public AppOperationResult Update(int id, LocalDto localDto)
    {
        var appOperationResult = CommunValidations.IsDtoNull(localDto);
        if (appOperationResult != null) return appOperationResult;

        var tupleValidation = localDto.IsModelDtoValidateForUpdate(id);
        var isValidate = tupleValidation.Item1;

        if (isValidate)
        {
            if (TryUpdateLocalFromLocalDto(id, localDto)) return AppOperationResult.Successful();
        }
        string messageError = tupleValidation.Item2;
        return AppOperationResult.WithError(messageError);
    }

这些是我添加正面和负面局部的方法(我称之为AdjacentLocals):

 public AppOperationResult AddAdjacentLocalsToLocal(AdjacentLocalsToLocalDto adjacentLocalsToLocal)
    {
        var localDto = adjacentLocalsToLocal.LocalToModify;
        var appOperationResult = CommunValidations.IsDtoNull(localDto);
        if (appOperationResult != null) return appOperationResult;
        var tupleValidation = localDto.IsModelDtoValidate();
        var isValidate = tupleValidation.Item1;

        if (isValidate)
        {
            if (TryToAddAdjacentLocalsToLocal(adjacentLocalsToLocal, localDto))
                return AppOperationResult.Successful();
        }
        string messageError = tupleValidation.Item2;
        return AppOperationResult.WithError(messageError);
    }

    private bool TryToAddAdjacentLocalsToLocal(AdjacentLocalsToLocalDto adjacentLocalsToLocal, LocalDto localDto)
    {
        var positiveLocals = adjacentLocalsToLocal.PositiveLocals;
        var negativeLocals = adjacentLocalsToLocal.NegativeLocals;

        var positiveslocalsRepeated = positiveLocals.Intersect(localDto.PositivesLocalsDtos);
        positiveLocals.RemoveAll(x => positiveslocalsRepeated.Contains(x));

        var negativeslocalsRepeated = negativeLocals.Intersect(localDto.NegativesLocalsDtos);
        negativeLocals.RemoveAll(x => negativeslocalsRepeated.Contains(x));

        localDto.PositivesLocalsDtos = new List<LocalDto>(positiveLocals);
        localDto.NegativesLocalsDtos = new List<LocalDto>(negativeLocals);

        return TryUpdateLocalFromLocalDto(localDto.Id, localDto);
    }

    private bool TryUpdateLocalFromLocalDto(int idLocal, LocalDto localDto)
    {
        var local = _localServices.GetById(idLocal);
        local.PositivesLocals.Clear();
        local.NegativesLocals.Clear();
        _localServices.Update(local);
        if (local != null)
        {
            localDto.Id = idLocal;
            var localUpdated = _mappingServices.Map(localDto, local);
            _localServices.Update(localUpdated);

            return true;
        }
        return false;
    }

******** LocalDto *************

 public class LocalDto
{
    public int Id { get; set; }

    public string Number { get; set; }

    public float Volumen { get; set; }

    public int NumberMaxPeople { get; set; }

    public SectionDto SectionDto { get; set; }       

    public List<LocalDto> PositivesLocalsDtos { get; set; }

    public List<LocalDto> NegativesLocalsDtos { get; set; }
}

我正在使用ASP.NET WEB API理念,这就是为什么我用JSON(正确)传递相邻位置的列表,因为我认为列表中的对象与之间的关系数据库记录丢失了,但我不明白为什么,因为这些本地DTO正确映射并返回相应的本地对象。但是,当我更新一个本地没有任何正面或负面的本地列表,没有问题..所以我认为这个问题是与自我多对多的关系。

我已经多次跟踪代码,我检查所有实体是否都有关系,一切似乎都没问题,但是当我尝试更新本地实体时插入邻接本地(正本和负本地)给我的错误是我上面提到过。所以我 。我等待你的回答。退休

1 个答案:

答案 0 :(得分:0)

我认为正在发生的是以下某些实体实体框架,当您使用automapper服务时,它不会链接数据库中的现有部分,因此我建议您在Dto中不使用其他dto的关系,例如:

public class LocalDto

{     public int Id {get;组; }

public string Number { get; set; }

public float Volumen { get; set; }

public int NumberMaxPeople { get; set; }

public SectionDto SectionDto { get; set; }       

public List<LocalDto> PositivesLocalsDtos { get; set; }

public List<LocalDto> NegativesLocalsDtos { get; set; }

}

将其更改为:

 public class LocalDto

{     public int Id {get;组; }

public string Number { get; set; }

public float Volumen { get; set; }

public int NumberMaxPeople { get; set; }

public int SectionId { get; set; }       

public List<LocalDto> PositivesLocalsDtos { get; set; }

public List<LocalDto> NegativesLocalsDtos { get; set; }

}

并且您还必须更改与这些实体关联的映射器,这必须从LocalMappers类中删除,

 .ForMember(localDto => localDto.SectionDto, mc => mc.MapFrom(local => local.Section));

此解决方案适用于所有具有关系的Dtos,将它们与与之相关的实体的ID链接,而不是与Dtos相关联 我希望我帮助了