【问题标题】:How do I use Automapper to map changes to an existing collection?如何使用 Automapper 将更改映射到现有集合?
【发布时间】:2015-03-25 14:05:00
【问题描述】:

我有一些相当简单的代码可以将用户对视图模型中集合的更改应用到模型中的集合。

public void Apply(ViewModelListItem source, ICollection<ModelListItem> dest)
{
    //user added and removed an item before saving, do nothing
    if (source.Insert && source.Delete) return;

    //user added an item
    if (source.Insert)
    {
        dest.Add(Mapper.Map<T>(source));
    }

    //user deleted an item
    else if (source.Delete)
    {
        //Using custom Equals implementation that compares PK
        dest.Remove(dest.FirstOrDefault(destItem => source.Equals(destItem)));
    }

    //user modified or did not alter an item
    else
    {
        //Using custom Equals implementation that compares PK
        Mapper.Map(source, dest.FirstOrDefault(destItem => source.Equals(destItem)));
    }
}

...

foreach (var item in MyViewModel.MyCollection)
{
    Apply(item, MyModel.MyCollection);
}

我在代码中的多个位置使用了这种模式,因此我一直在寻找一种以通用方式重用代码的方法。 Automapper 是否有办法简单地将引用传递给源/目标并让我在其上运行我自己的设置逻辑?如果没有,有没有其他方法可以使这段代码通用,这样我就不必为每个新的视图模型编写它?

【问题讨论】:

  • 您找到答案了吗?我也有同样的问题。
  • 添加了我的解决方案作为答案。注意:由于其他原因,我最终放弃了 automapper,但仍然使用相同的想法来映射集合,只是减去了 automapper 集成。

标签: c# generics mapping viewmodel automapper


【解决方案1】:

看看AutoMapper.Collection。它自动处理集合上的所有 CRUD 操作:

将根据用户定义的源集合和目标集合的通用项目类型之间的等效性,从预先存在的集合对象中添加/更新/删除项目

【讨论】:

    【解决方案2】:

    我的解决方案:

    Viewmodel 的基类:

    public abstract class ListItemViewModel<T>
    {
        public bool Insert { get; set; }
        public bool Delete { get; set; }
    
        public abstract bool Equals(T model);
    
        public virtual void OnRemove(T model) { }
        public virtual void OnAdd(T model) { }
        public virtual void OnEdit(T model) { }
    }
    

    辅助函数:

    public static class MapConfiguration
    {
        public static void MapCollection<T>(IEnumerable<ListItemViewModel<T>> source, ICollection<T> dest)
        {
            foreach (var sourceItem in source)
            {
                //user added and removed an item before saving, do nothing
                if (sourceItem.Insert && sourceItem.Delete) continue;
    
                //user added an item
                if (sourceItem.Insert)
                {
                    var destItem = Mapper.Map<T>(sourceItem);
                    sourceItem.OnAdd(destItem);
                    dest.Add(destItem);
                }
    
                //user deleted an item
                else if (sourceItem.Delete)
                {
                    //Using custom Equals implementation that compares PK
                    var destItem = dest.First(d => sourceItem.Equals(d));
                    sourceItem.OnRemove(destItem);
                    dest.Remove(destItem);
                }
    
                //user modified or did not alter an item
                else
                {
                    //Using custom Equals implementation that compares PK
                    var destItem = dest.First(d => sourceItem.Equals(d));
                    sourceItem.OnEdit(destItem);
                    Mapper.Map(sourceItem, destItem);
                }
            }
        }
    }
    

    实施:

    • 创建一个继承自 ListItemViewModel 的视图模型类,其中 T 是模型类型
    • 实现Equals(T model)方法,使辅助函数可以匹配枚举中的现有元素
    • 将具有 ListItemViewModel 继承类型的通用可枚举属性添加到您的主视图模型中

    当您配置自动映射器时,您现在可以使用以下内容:

    .ForMember(m => m.MyList, opt => opt.Ignore())
    .AfterMap((vm, m) => MapConfiguration.MapCollection(vm.MyList, m.MyList)) 
    

    此代码将执行以下操作:

    • 如果设置了Insert 标志,则将新项目添加到您的收藏中
    • 如果设置了 Remove 标志,则从您的收藏中删除项目
    • 如果未设置任何标志,则执行 Automapper 映射

    【讨论】:

      猜你喜欢
      • 2015-03-18
      • 1970-01-01
      • 2023-04-04
      • 1970-01-01
      • 2020-12-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多