gpt4 book ai didi

c# - 使用 Automapper 映射自引用关系

转载 作者:行者123 更新时间:2023-12-03 09:39:54 25 4
gpt4 key购买 nike

我有一个涉及 .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; }
}

这使得在用户模型中保留“关注者”和“关注者”列表成为可能:
public class ApplicationUser : IdentityUser
{
//...
public ICollection<Network> Following { get; set; }
public ICollection<Network> Followers { get; set; }
}

我使用 Automapper 将关注者和关注列表映射到 View 模型。以下是 View 模型:
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; }
}

考虑到追随者和追随者被映射的不同方式,我不得不创建两个相同的类: NetworkUserViewModelFollowerViewModel以便 Automapper 映射逻辑可以区分如何映射关注者和如何映射关注者。这是映射配置文件:
         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();

你可以看到关注者被映射为 .MapFrom(x => x.Follower.UserName))而以下用户被映射为 .MapFrom(x => x.ApplicationUser.UserName)) .

我的问题是:我可以定义映射关注者和关注用户的不同方式而不必定义重复的类吗?我更愿意使用 NetworkUserViewModel为关注 追随者;这样我就不需要重复的 FollowerViewModel , 如果可能的话。有没有办法做到这一点?

更新

我已经实现了@Matthijs(见第一条评论)的建议,使用继承来避免不必要的属性重复。我的 View 模型现在是这些:
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
{
}

对 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();

这种重构减少了重复并使映射逻辑更易于遵循。

我将这个开放几天,以防万一有一个纯粹依赖于 Automapper 逻辑的解决方案......

最佳答案

您遇到问题的原因是目标对象相同,但 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;
}
}
并将其添加到 Mapper 配置中:
CreateMap<SourceObjectA, MyResponseObject>()
.ForMember(dest => dest.ObjectA, src => src.MapFrom<MappingResolver>());

CreateMap<SourceObjectB, MyResponseObject>()
.ForMember(dest => dest.ObjectB, src => src.MapFrom<MappingResolver>());

关于c# - 使用 Automapper 映射自引用关系,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55669398/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com