ABP的IObjectMapper.Map的神奇BUG?谨慎使用List的Mapper?

71 阅读3分钟

前言

ABP中有一个很好的思想,我认为就是Dto+Mapper 说白点就是一个数据库表,你在API中,或者是UI中需要以什么业务展示,就拆分成多个Dto 按照需要的情况去添加或者缩减字段 比如登录,你只要账号和密码,再添加一些其他字段等 如果是注册,有注册的字段 最后在提交给数据库前通过Map把数据转化成数据库表的信息,最后更新或者是写入等! 问题 后面我发现有这么一个问题!!!

直接代码

先看代码

        /// <summary>
        /// 批量编辑
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost]
        [TypeFilter(typeof(RoleAttribute), Arguments = new object[] { "data", "edit" })]
        public async Task<string> BatchUpdate(List<DragAttributeInfoUpdateDto> input)
        {
            var ids = input.Where(x => x.Id != 0).Select(x => x.Id).ToArray();
            var infos = await _dbContext.DragAttributeInfo.Where(x => ids.Contains(x.Id)).ToListAsync();
            if (infos?.Any() == false)
            {
                throw new PasteCodeException("没有获得有效数据,请确认数据是否正确!");
            }

            //方法一
            foreach (var item in infos)
            {
                var find = input.Where(x => x.Id == item.Id).FirstOrDefault();
                if (find != null && find != default)
                {
                    ObjectMapper.Map<DragAttributeInfoUpdateDto, DragAttributeInfo>(find, item);
                }
            }

            //方法二
            //打印input可以获得新的数据,标识上面的转化是正常的,其实不正常上面也就报错了,因为读取不到数据
            //ObjectMapper.Map<List<DragAttributeInfoUpdateDto>, List<DragAttributeInfo>>(input, infos);
            //打印infos可以看到数据已经转换了

            await _dbContext.SaveChangesAsync();

            return "批量编辑完成,刷新后可见!";
        }

上面代码,你肯定会说用方法二就行了,简单干净,干嘛要搞方法一? 再看看另外一个代码

        /// <summary>
        /// 批量编辑
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost]
        [TypeFilter(typeof(RoleAttribute), Arguments = new object[] { "data", "edit" })]
        public async Task<string> BatchUpdate(List<DragAttributeValueUpdateDto> input)
        {
            var ids = input.Where(x => x.Id != 0).Select(x => x.Id).ToArray();
            var infos = await _dbContext.DragAttributeValue.Where(x => ids.Contains(x.Id)).ToListAsync();
            if (infos?.Any() == false)
            {
                throw new PasteCodeException("没有获得有效数据,请确认数据是否正确!");
            }
            foreach (var item in infos)
            {
                var find = input.Where(x => x.Id == item.Id).FirstOrDefault();
                if (find != null && find != default)
                {
                    find.DragAttributeId = item.DragAttributeId;
                }
            }
            ObjectMapper.Map<List<DragAttributeValueUpdateDto>, List<DragAttributeValue>>(input, infos);
            await _dbContext.SaveChangesAsync();
            return "批量编辑完成,刷新后可见!";
        }

其实站我角度,我是真的不理解的,为啥片段一的方法一不行呢!!!

数据模型

一起来看看他们的数据模型

    ///<summary>
    ///属性
    ///</summary>
    public class DragAttributeInfoAddDto
    {

        ///<summary>
        ///名称 
        ///</summary>
        [MaxLength(16)]
        [Required]
        public string Name { get; set; }

        ///<summary>
        ///状态
        ///</summary>
        public bool IsEnable { get; set; } = true;

        ///<summary>
        ///排序
        ///</summary>
        public int Sort { get; set; }

        ///<summary>
        ///描述
        ///</summary>
        [MaxLength(64)]
        public string Desc { get; set; } = "";

        ///<summary>
        ///备注
        ///</summary>
        [MaxLength(64)]
        public string Mark { get; set; } = "";
    }

    ///<summary>
    ///属性
    ///</summary>
    public class DragAttributeInfoUpdateDto : DragAttributeInfoAddDto
    {

        ///<summary>
        ///ID
        ///</summary>
        [PasteHidden]
        public int Id { get; set; }

    }

另外一个的

    ///<summary>
    ///属性值 记录每一个属性的可选值
    ///</summary>
    public class DragAttributeValueAddDto
    {

        ///<summary>
        ///属性
        ///</summary>
        [PasteQuery("attribute_id", true)]
        [PasteRequired]
        public int DragAttributeId { get; set; }

        ///<summary>
        ///值 示例3,3.2
        ///</summary>
        [MaxLength(16)]
        public string Value { get; set; }

        ///<summary>
        ///默认选中
        ///</summary>
        public bool Default { get; set; } = false;

        ///<summary>
        ///排序
        ///</summary>
        public int Sort { get; set; }

        ///<summary>
        ///描述
        ///</summary>
        [MaxLength(128)]
        public string Desc { get; set; }
    }

    ///<summary>
    ///属性值 记录每一个属性的可选值
    ///</summary>
    public class DragAttributeValueUpdateDto : DragAttributeValueAddDto
    {

        ///<summary>
        ///ID
        ///</summary>
        [PasteHidden]
        public int Id { get; set; }

    }

我实在是没发现有啥特殊的地方 上面的Paste特性是PasteForm框架的特性,里面并没有校验啥的,相当于没写一样,就这样的,居然一个Mapper.List成功,一个Mapper.List失败?

测试结果

正和上面的方法二注释的那样,其实并不是Mapper的问题? 或者说也是Mapper的问题 我们都知道Mapper其实干了2件事 1.按照Mapper规则,对对应字段进行变更 2.标记这个实体的这个字段的变更属性为true,也就是Tracker的EntityState 可是测试结果就是,保存没报错,重新读取数据后,发现数据没更新 别和我说某一个字段,我是能改的字段都改了测试,结果一样!!!

回想

其实这个问题我以前也遇到过一次,就是做商城的SKU的时候,一开始我也是List直接Mapper的,结果死活对不上数据,后面不得不拆开一个一个属性赋值的!!! 后面我感觉优点问题,会不会是List的问题,改成和上面的方法二一样的测试了下可以了。。。。 我有种想吐的感觉! 后面事情多了,也就忘了继续深究了 今天又被我碰到了 先做一下记录 后续我看看啥问题 如果你知道是啥问题产生的,欢迎在评论区留言!!!