【问题标题】:Return all items in source list when using automapper to map to existing list使用自动映射器映射到现有列表时返回源列表中的所有项目
【发布时间】:2019-10-16 18:41:43
【问题描述】:

我有一个从数据库加载的对象列表,我们称它们为“MyObjects”,然后我有一个从单独数据库加载的扩展对象“ExtensionsObjects”列表。我使用 automapper 将这些扩展对象的一些属性映射到“MyObjects”。 (扩展对象包含 MyObject 的关键字段)

这可行,字段从 ExtentionObject 正确映射到 MyObject,但自动映射器返回一个列表,该列表仅返回“ExtensionObject”映射到的那些“MyObjects”。 (并且没有扩展对象的 MyObject 是完全有效的情况)。

我用于映射的代码:

//first get the lists of MyObjects and ExtentionObjects
List<MyObject> myObjects = GetMyObjects(); 
List<ExtentionObject> extentionObjects = GetExtentionObjects(); 

//execute the mapping (_mapper is my automapper)
myObjects = _mapper.Map(extentionObjects, myObjects); 

//myObject now contains less objects than before the call to the mapper

自动映射器配置的代码(cfg 是用于创建映射器的映射器配置):

cfg.CreateMap<ExtentionObject, MyObject>()
    .EqualityComparison((eo, my)=> CheckForEquality(eo, my))
    .ForMember(....)
    .ForMember(....)
    .ReverseMap().ConvertUsing((mo, eo)=> 
    {
        var ext = new ExtentionObect();
        ...
        return ext;
    });

相等性检查功能只是检查 ExtentionObject 和 MyObject 的 ID 是否匹配。

我希望结果列表包含原始“myObjects”列表中的所有项目。 ExtentionObject 实例中的信息应添加到相应的 MyObject 实例中,但由于 Extention 是可选的,因此所有“MyObjects”必须保留在结果列表中。

假设我的数据库包含带有键 1、2,3 的 MyObjects 和带有键 1 和 3 的 ExtentionObjects。

//before this cal myObjects contains 3 items, ExentionObjects contains 2
myObjects = _mapper.Map(extentionObjects, myObjects); 
//after this cal myObjects contains only 2 items, 
//with the properties from Extentionobject 1 and 3 correctly mapped to MyObject 1 and 3, 
//ERROR => MyObject 2 has "disappeared" from the 'destination' list

问题是“如何将对象 2 保留在我的列表中”?

【问题讨论】:

  • 使用IEqualityComparer 的自定义对象比较器怎么样?
  • 我尝试过使用自定义 ITypeConvertor (但存在一些问题(如果我没记错的话,代码是前段时间编写的,测试需要一些时间......)。但问题不会是一样吗?不会添加未从 ExtensionObject 映射的对象(我猜)我还忘了提到我调用 ReverseMap() 能够反转映射。
  • stackoverflow.com/questions/6694508/… 您可以从这里了解如何根据需要完成自定义比较而不是 ID 比较。
  • @Aarif,感谢您的输入,但为什么 IEqualityComparer 会有任何其他结果?我的 EqualityCoparison 工作得很好,比如说我有带有键 1、2、3 的 MyObjects 和带有键 1 和 3 的 Extention 对象。结果列表包含 2 个 MyObjects(1 和 3),其属性从 Extention 对象 1 和 3 映射。但是 结果列表中缺少 MyObject 2
  • 您的问题仍然不清楚,“我希望结果列表包含完全相同数量的项目”,这应该如何以及为什么会这样工作?这无法通过一些框架魔法来实现,您必须为此更改比较标准

标签: c# automapper


【解决方案1】:

经过进一步调查,发现问题不在于 Automapper 本身,而在于 Automapper.Collections(automapper 到地图集合的扩展)。在其github repo 上提出了相同功能的问题,但没有真正的解决方案。尽管有关于如何修改 automapper.collection 以避免删除的建议,但从长远来看,我认为分叉这个存储库并不明智。 然而,对于从列表中删除项目的位置有一个指示。它使用 ICollection.Remove() 方法(不是清除然后添加值)。

所以我的解决方案是将我的列表包装在具有“删除”的“nop”实现的“EditOnlyCollection”中。 (在我的情况下,其他方法也有一个“nop”,但这很容易改变)。 注意:它不适用于 ReadOnlyCollection 中的构建,因为它会在 remove 方法中引发异常。

class EditOnlyCollection<T> : ICollection<T>
    {
        private readonly List<T> list;

        public EditOnlyCollection(IEnumerable<T> list)
        {
            this.list = list.ToList();
        }

        public int Count => list.Count;

        public bool IsReadOnly => true;

        public void Add(T item)
        {
            //nop
        }

        public void Clear()
        {
            //nop
        }

        public bool Contains(T item)
        {
            return list.Contains(item);
        }

        public void CopyTo(T[] array, int arrayIndex)
        {
            list.CopyTo(array, arrayIndex);
        }

        public IEnumerator<T> GetEnumerator()
        {
            return list.GetEnumerator();
        }

        public bool Remove(T item)
        {
            //nop
            return true; //have them think we removed an item
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return list.GetEnumerator();
        }
    }

【讨论】:

    猜你喜欢
    • 2021-10-28
    • 2017-10-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多