如何使用 Automapper 将更改映射到现有集合?
How do I use Automapper to map changes to an existing collection?
我有一些相当简单的代码,可以将用户对视图模型中集合的更改应用到模型中的集合。
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 是否有办法简单地传递对 source/destination 的引用并让我 运行 我自己的设置逻辑?如果没有,是否有任何其他方法可以使此代码通用,这样我就不必为每个新视图模型都编写它?
我的解决方案:
Viewmodel 的基础 class:
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
的视图模型 class,其中 T 是模型类型
- 实现
Equals(T model)
方法,使辅助函数可以匹配可枚举 中的现有元素
- 将具有 ListItemViewModel 继承类型的通用可枚举 属性 添加到您的主视图模型
配置自动映射器时,您现在可以使用以下内容:
.ForMember(m => m.MyList, opt => opt.Ignore())
.AfterMap((vm, m) => MapConfiguration.MapCollection(vm.MyList, m.MyList))
此代码将执行以下操作:
- 如果设置了
Insert
标志,则向 collection 添加新项目
- 如果设置了
Remove
标志,请从您的 collection 中删除项目
- 如果两个标志都未设置,则执行 Automapper 映射
看看AutoMapper.Collection。它自动处理集合上的所有 CRUD 操作:
Will Add/Update/Delete items from a preexisting collection object based on user defined equivalency between the collection's generic item type from the source collection and the destination collection
我有一些相当简单的代码,可以将用户对视图模型中集合的更改应用到模型中的集合。
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 是否有办法简单地传递对 source/destination 的引用并让我 运行 我自己的设置逻辑?如果没有,是否有任何其他方法可以使此代码通用,这样我就不必为每个新视图模型都编写它?
我的解决方案:
Viewmodel 的基础 class:
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
的视图模型 class,其中 T 是模型类型 - 实现
Equals(T model)
方法,使辅助函数可以匹配可枚举 中的现有元素
- 将具有 ListItemViewModel 继承类型的通用可枚举 属性 添加到您的主视图模型
配置自动映射器时,您现在可以使用以下内容:
.ForMember(m => m.MyList, opt => opt.Ignore())
.AfterMap((vm, m) => MapConfiguration.MapCollection(vm.MyList, m.MyList))
此代码将执行以下操作:
- 如果设置了
Insert
标志,则向 collection 添加新项目 - 如果设置了
Remove
标志,请从您的 collection 中删除项目 - 如果两个标志都未设置,则执行 Automapper 映射
看看AutoMapper.Collection。它自动处理集合上的所有 CRUD 操作:
Will Add/Update/Delete items from a preexisting collection object based on user defined equivalency between the collection's generic item type from the source collection and the destination collection