AutoMapper 使用 ConvertUsing 自定義類型轉換,將包含串列成員的物件映射為一組串列
從朋友那兒聽到了用 AutoMapper 把串列成員物件攤平成一組串列的問題,發現了 ConvertUsing 的好用,這邊就紀錄一下。
事情是這樣的,首先有一個 Parent
類別,其中包含著兩個成員:Id
和串列的 Child
類別,而 Child
類別則只有一個成員 Val
,如下:
public class Parent
{
public int Id { get; set; }
public IEnumerable<Child> Children { get; set; }
}
public class Child
{
public double Val { get; set; }
}
另外還有一個 Target
類別,包含 Id
和 Val
兩個成員:
public class Target
{
public int Id { get; set; }
public double Val { get; set; }
}
現在的目標是:將一個有著 Child 串列的 Parent 映射成 Target 串列。
也就是說,假設我們的來源是這樣子:
var boo = new Parent
{
Id = 1,
Children = new List<Child>
{
new Child { Val = 1 },
new Child { Val = 2 },
}
};
希望可以變成這樣子:
var expect = new List<Target>
{
new Target { Id = 1, Val = 1 },
new Target { Id = 1, Val = 2 },
};
我之前遇到的時候,會直覺地將 Child 直接 Map 到 Target,再對 Target 做個 Foreach 來補上 Parent 的 Id。
這次和朋友討論時,提到了另一個角度:雖然這樣的做法相當直覺快速,但其實並不能保證後續維護的人使用這組 Mappings 時,都知道這裡要補資料;況且此處的對應關係的確是 Parent
到 List<Target>
,並非 Child
到 Target
而已,直覺上就怪怪的。若要解決這個問題,可能就要再包裝一層,把 Mapper 隔離出去做個轉換器之類的。
但想想又覺得 AutoMapper 不可能沒提供這個場景能使用的方法才對,最後餵狗發現 AutoMapper 確實有提供 ConvertUsing
來讓我們客製化轉換過程,這邊就紀錄一下。
在我們註冊映射關係的時候,可以用 ConvertUsing
來直接定義轉換的過程。以這個例子來說,就可以:
var config = new MapperConfiguration(cfg =>
{
cfg
.CreateMap<Parent, IEnumerable<Target>>()
.ConvertUsing(parent => parent.Children.Select(child => new Target
{
Id = parent.Id,
Val = child.Val
}));
});
像這樣告訴 AutoMapper:「從 Parent
轉換到 IEnumerable<Target>
的時候,幫我用 Children 來 Select 出 Target」
註冊後就可以順利進行轉換了,讓我們直接用 Linqpad 試試:
如果是比較複雜的狀況,也可以用實作型別轉換器(ITypeConverter
)的方式來處理。以這個例子來說,就可以:
// c實作從 Parent 轉換到 IEnumerable<Target> 的 ITypeConverter
public class ParentToTargetsTypeConverter : ITypeConverter<Parent, IEnumerable<Target>>
{
// 轉換方法本體
public IEnumerable<Target> Convert(
Parent parent,
IEnumerable<Target> targets,
ResolutionContext context)
{
targets = parent.Children.Select(child => new Target
{
Id = parent.Id,
Val = child.Val
});
return targets;
}
}
接著再把轉換器註冊到 ConvertUsing
上,丟實體或是泛型都行:
var config = new MapperConfiguration(cfg =>
{
//cfg
// .CreateMap<Parent, IEnumerable<Target>>()
// .ConvertUsing(new ParentToTargetsTypeConverter());
// OR
cfg
.CreateMap<Parent, IEnumerable<Target>>()
.ConvertUsing<ParentToTargetsTypeConverter>();
});
測試轉換:
之後當遇到型別轉換的過程並非單純欄位一對一的時候,就可以使用 ConvertUsing 的方式來自行處理。
最後附上測試用的 Linqpad Code 方便我之後回來複製
void Main()
{
Sut().Dump();
}
public IEnumerable<Target> Sut()
{
var boo = new Parent
{
Id = 1,
Children = new List<Child>
{
new Child { Val = 1 },
new Child { Val = 2 },
}
};
var mapper = CreateMapperConfig().CreateMapper();
var result = mapper.Map<Parent, IEnumerable<Target>>(boo);
return result;
}
public MapperConfiguration CreateMapperConfig()
{
var config = new MapperConfiguration(cfg =>
{
// 1. 使用 Lambda
//cfg
// .CreateMap<Parent, IEnumerable<Target>>()
// .ConvertUsing(parent => parent.Children.Select(child => new Target
// {
// Id = parent.Id,
// Val = child.Val
// }));
// 2. 使用 TypeConverter
//cfg
// .CreateMap<Parent, IEnumerable<Target>>()
// .ConvertUsing(new ParentToTargetsTypeConverter());
cfg
.CreateMap<Parent, IEnumerable<Target>>()
.ConvertUsing<ParentToTargetsTypeConverter>();
});
return config;
}
public class ParentToTargetsTypeConverter : ITypeConverter<Parent, IEnumerable<Target>>
{
public IEnumerable<Target> Convert(
Parent parent,
IEnumerable<Target> targets,
ResolutionContext context)
{
targets = parent.Children.Select(child => new Target
{
Id = parent.Id,
Val = child.Val
});
return targets;
}
}
public class Parent
{
public int Id { get; set; }
public IEnumerable<Child> Children { get; set; }
}
public class Child
{
public double Val { get; set; }
}
public class Target
{
public int Id { get; set; }
public double Val { get; set; }
}
參考資料
- AutoMapper 之自定义类型转换器(Custom Type Converters) - 简书
- AutoMapper官方文档(十一)【自定义类型转换器】_极客神殿 - CSDN博客
- [小菜一碟] C# 中一個古老的好物 - TypeConverter | 軟體主廚的程式料理廚房 - 點部落
- c# - Automapper: Map single object with list of objects inside to just list - Stack Overflow
- c# - Possible to use AutoMapper to map one object to list of objects? - Stack Overflow
- c# - use automapper to map single object into a list of objects - Stack Overflow
相關文章
其他文章
哈囉,如果你也有 LikeCoin,也覺得我的文章有幫上忙的話,還請不吝給我拍拍手呦,謝謝~ ;)