Win*_*rpe 7 c# automapper asp.net-core
我有一个涉及.NET Core的自引用关系ApplicationUser:
public class Network
{
public ApplicationUser ApplicationUser { get; set; }
public string ApplicationUserId { get; set; }
public ApplicationUser Follower { get; set; }
public string FollowerId { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
这样就可以在用户模型中保留“关注者”和“关注者”的列表:
public class ApplicationUser : IdentityUser
{
//...
public ICollection<Network> Following { get; set; }
public ICollection<Network> Followers { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
我使用Automapper将关注者和关注列表映射到视图模型。这是视图模型:
public class UserProfileViewModel
{
//...
public IEnumerable<FollowerViewModel> Followers { get; set; }
public IEnumerable<NetworkUserViewModel> Following { get; set; }
}
public class NetworkUserViewModel
{
public string UserName { get; set; }
public string ProfileImage { get; set; }
public bool IsFollowing { get; set; } = true;
public bool IsOwnProfile { get; set; }
}
public class FollowerViewModel
{
public string UserName { get; set; }
public string ProfileImage { get; set; }
public bool IsFollowing { get; set; } = true;
public bool IsOwnProfile { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
为了考虑跟随者和跟随者映射的不同方式,我不得不创建两个相同的类:NetworkUserViewModel并且FollowerViewModelAutomapper映射逻辑可以区分如何映射跟随者和如何映射跟随者。这是映射配置文件:
CreateMap<Network, NetworkUserViewModel>()
.ForMember(x => x.UserName, y => y.MapFrom(x => x.ApplicationUser.UserName))
.ForMember(x => x.ProfileImage, y => y.MapFrom(x => x.ApplicationUser.ProfileImage))
.ReverseMap();
CreateMap<Network, FollowerViewModel>()
.ForMember(x => x.UserName, y => y.MapFrom(x => x.Follower.UserName))
.ForMember(x => x.ProfileImage, y => y.MapFrom(x => x.Follower.ProfileImage))
.ReverseMap();
CreateMap<ApplicationUser, UserProfileViewModel>()
.ForMember(x => x.UserName, y => y.MapFrom(x => x.UserName))
.ForMember(x => x.Followers, y => y.MapFrom(x => x.Followers))
.ForMember(x => x.Following, y => y.MapFrom(x => x.Following))
.ReverseMap();
Run Code Online (Sandbox Code Playgroud)
您可以看到关注者的映射方式类似于,.MapFrom(x => x.Follower.UserName))而关注用户的映射方式则类似于.MapFrom(x => x.ApplicationUser.UserName))。
我的问题是:是否可以定义映射关注者和关注用户的不同方式,而不必定义重复的类?我宁愿使用NetworkUserViewModelfor跟随者和跟随者;因此FollowerViewModel,如果可能的话,我不需要重复的副本。有办法吗?
更新资料
我已经实现了@Matthijs的建议(请参阅第一个评论),以使用继承来避免不必要的属性重复。我的视图模型现在是这些:
public class UserProfileViewModel
{
//...
public IEnumerable<FollowerViewModel> Followers { get; set; }
public IEnumerable<FollowingViewModel> Following { get; set; }
}
public class NetworkUserViewModel
{
public string UserName { get; set; }
public string ProfileImage { get; set; }
public bool IsFollowing { get; set; }
public bool IsOwnProfile { get; set; }
}
public class FollowingViewModel : NetworkUserViewModel
{
}
public class FollowerViewModel : NetworkUserViewModel
{
}
Run Code Online (Sandbox Code Playgroud)
对Automapper逻辑进行以下更改:
CreateMap<Network, FollowingViewModel>()
.ForMember(x => x.UserName, y => y.MapFrom(x => x.ApplicationUser.UserName))
.ForMember(x => x.ProfileImage, y => y.MapFrom(x => x.ApplicationUser.ProfileImage))
.ReverseMap();
CreateMap<Network, FollowerViewModel>()
.ForMember(x => x.UserName, y => y.MapFrom(x => x.Follower.UserName))
.ForMember(x => x.ProfileImage, y => y.MapFrom(x => x.Follower.ProfileImage))
.ReverseMap();
CreateMap<ApplicationUser, UserProfileViewModel>()
.ForMember(x => x.UserName, y => y.MapFrom(x => x.UserName))
.ForMember(x => x.Followers, y => y.MapFrom(x => x.Followers))
.ForMember(x => x.Following, y => y.MapFrom(x => x.Following))
.ReverseMap();
Run Code Online (Sandbox Code Playgroud)
这种重构减少了重复,并使映射逻辑更易于遵循。
我将开放几天,以防万一有一个解决方案完全依赖于Automapper逻辑...
小智 1
您遇到问题的原因是目标对象是相同的,但 Automapper 无法推断它。Automapper 只是使用反射来查找具有相同名称的变量。
对于复杂的映射,下次可以考虑编写自定义映射器。这为您提供了极大的灵活性,并简化了您的映射配置。您可以创建自定义映射解析器以从任何源返回所需的对象,即使您指定了多个源也是如此。您将源映射到您自己的目标成员。我发现这非常好,将来可能会对您有所帮助。它的工作原理如下:
解析器:
public class MappingResolver: IValueResolver<object, object, MyResponseObject>
{
// Automapper needs parameterless constructor
public MappingResolver()
{
}
// Resolve dependencies here if needed
public MappingResolver(IWhateverINeed whateverINeed)
{
}
public MyResponseObject Resolve(
object source, object destination, MyResponseObject> destMember, ResolutionContext context)
{
if (source.GetType() == typeof(NetworkUserViewModel)
{
// Specific logic for source object, while destination remains the same response
var castedObject = source as NetworkUserViewModel;
return MyResponseObject;
}
Run Code Online (Sandbox Code Playgroud)
}
并将其添加到 Mapper 配置中:
CreateMap<SourceObjectA, MyResponseObject>()
.ForMember(dest => dest.ObjectA, src => src.MapFrom<MappingResolver>());
CreateMap<SourceObjectB, MyResponseObject>()
.ForMember(dest => dest.ObjectB, src => src.MapFrom<MappingResolver>());
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
266 次 |
| 最近记录: |