我刚刚开始使用automapper来映射DTO< - >实体,它看起来效果很好。
在某些特殊情况下,我只想映射一些属性并执行其他检查。没有automapper,代码看起来像这样(使用fasterflect的PropertyExtensions):
object target;
object source;
string[] changedPropertyNames = { };
foreach (var changedPropertyName in changedPropertyNames)
{
var newValue = source.GetPropertyValue(changedPropertyName);
target.SetPropertyValue(changedPropertyName, newValue);
}
当然,如果需要进行类型转换,此代码将无效。 Automapper使用内置的TypeConverters,我还创建了一些特定的TypeConverter实现。
现在我想知道是否可以映射单个属性并使用automapper的类型转换实现,类似这样的
Mapper.Map(source, target, changedPropertyName);
我认为有必要提供更多信息:
我已经创建了一些地图,例如
Mapper.CreateMap<CalendarEvent, CalendarEventForm>()
我还在CalendarEvent中为可为空的dateTime属性创建了一个带有自定义typeconverter的地图,例如。
Mapper.CreateMap<DateTimeOffset?, DateTime?>().ConvertUsing<NullableDateTimeOffsetConverter>();
我在web api OData Controller中使用这些地图。发布新的EntityDTO时,我使用
Mapper.Map(entityDto, entity);
并将实体保存到数据存储区。
但是如果使用PATCH
,则会将Delta<TDto> entityDto
传递给我的控制器方法。因此,我需要调用entityDto.GetChangedPropertyNames()
并使用更改的值更新现有的持久实体。
基本上这适用于我的简单解决方案,但如果其中一个已更改的属性是一个DateTimeOffset
?我想使用我的NullableDateTimeOffsetConverter
。
答案 0 :(得分:18)
如果您只想映射一些选择属性,而不是如下所示:
// Create a map
var map = CreateMap<Source,Target>();
// ingnore all existing binding of property
map.ForAllMembers(opt => opt.Ignore());
// than map property as following
map.ForMember(dest => dest.prop1, opt => opt.MapFrom( src => src.prop1));
map.ForMember(dest => dest.prop2, opt => opt.MapFrom( src => src.prop2));
答案 1 :(得分:8)
您可以使用 MapFrom 方法进行投影 - http://automapper.readthedocs.io/en/latest/Projection.html
Mapper.Map(source, target)
.ForMember(m => m.Property, opt => opt.MapFrom(src => src.ChangedProperty));
例如(关注AutoMapper文档):
// Model
var calendarEvent = new CalendarEvent
{
Date = new DateTime(2008, 12, 15, 20, 30, 0),
Title = "Company Holiday Party"
};
// Configure AutoMapper
Mapper.CreateMap<CalendarEvent, CalendarEventForm>()
.ForMember(dest => dest.EventDate, opt => opt.MapFrom(src => src.Date.Date))
.ForMember(dest => dest.EventHour, opt => opt.MapFrom(src => src.Date.Hour))
.ForMember(dest => dest.EventMinute, opt => opt.MapFrom(src => src.Date.Minute));
答案 2 :(得分:1)
如果我正确地阅读了您的问题,是的,只要您的目的地(目标)属性与您的转化匹配。
因此,如果我从 override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
Randomize()
Hide()
authenticateLocalPlayer()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
@IBAction func Submit(sender: AnyObject) {
saveHighscore(Score)
showLeaderboard()
}
func authenticateLocalPlayer(){
var localPlayer = GKLocalPlayer.localPlayer()
localPlayer.authenticateHandler = {(viewController, error) -> Void in
if (viewController != nil) {
self.presentViewController(viewController, animated: true, completion: nil)
}
else {
println((GKLocalPlayer.localPlayer().authenticated))
}
}
}
func gameCenterViewControllerDidFinish(gameCenterViewController: GKGameCenterViewController!)
{
gameCenterViewController.dismissViewControllerAnimated(true, completion: nil)
}
func showLeaderboard() {
var vc = self.view?.window?.rootViewController
var gc = GKGameCenterViewController()
gc.gameCenterDelegate = self
vc?.presentViewController(gc, animated: true, completion: nil)
}
func saveHighscore(score:Int) {
//check if user is signed in
if GKLocalPlayer.localPlayer().authenticated {
var scoreReporter = GKScore(leaderboardIdentifier: "ChineseWeather") //leaderboard id here
scoreReporter.value = Int64(Score) //score variable here (same as above)
var scoreArray: [GKScore] = [scoreReporter]
GKScore.reportScores(scoreArray, withCompletionHandler: {(error : NSError!) -> Void in
if error != nil {
println("error")
}
})
}
}
转到string
bool
Status
或"A"
(有效/无效),我可以做类似的东西:
"I"
然后当转向另一个方向时,将其转换回来:
.ForMember(dest => dest.Status, opt => opt.MapFrom(src => src.Status == "A"))
日期示例:
.ForMember(dest => dest.Status, opt => opt.MapFrom(src => src.Status ? "A" : "I"))