将ID映射到控制器API的模型

时间:2019-01-10 12:24:23

标签: asp.net-core automapper

我在一个项目上使用asp.net core。 (我还很陌生)
我有一个用户模型。下面的代码是简化版本:

public class User
{
    public int id { get; set; }
    // attribute declaration
    public ICollection<User> friends { get; set; }
}

我正在使用自动映射器服务将我的api映射到该模型:

    public class UserResource
{
    public UserResource()
    {
        this.friendsId = new List<int>();

    }
    public int id { get; set; }
    // attribute declaration
    public ICollection<int> friendsId { get; set; }
}

以以下内容考虑对UserController的发布请求:

{ 
 "id" : 1
"friendsId": [2,3,4],
}

我想将friendsId中的整数映射到friends集合中每个用户的id。但我不知道该怎么办。这就是我所拥有的:

CreateMap<UserResource,User>()
            .ForMember(u => u.friends,opt => opt.MapFrom(????);

这是正确的方法吗?如果可以的话,该如何实施?
还是应该将数据库模型更改为此:

public class User
{
    public int id { get; set; }
    // attribute declaration
    public ICollection<int> friendsId { get; set; }
}

谢谢。

2 个答案:

答案 0 :(得分:1)

您将需要实现自定义值解析器。这些可以被注入,因此您可以在内部访问诸如上下文之类的东西:

public class FriendsResolver : IValueResolver<UserResource, User, ICollection<User>>
{
    private readonly ApplicationDbContext _context;

    public FriendsResolver(ApplicationDbContext context)
    {
        _context = context ?? throw new ArgumentNullException(nameof(context));
    }

    public ICollection<User> Resolve(UserResource source, User destination, ICollection<User> destMember, ResolutionContext context)
    {
        var existingFriendIds = destMember.Select(x => x.Id);
        var newFriendIds = source.friendsId.Except(existingFriendIds);
        var removedFriendIds = existingFriendIds.Except(source.Friends);

        destMember.RemoveAll(x => removedFriendIds.Contains(x.Id);
        destMember.AddRange(_context.Users.Where(x => newFriendIds.Contains(x.Id).ToList());

        return destMember;
    }
}

由于我只是将其放在这里,所以不确定是否可以按原样实际工作,但这足以使您继续工作。通常的想法是,将所需的任何东西注入值解析器,然后使用它来创建需要返回的实际内容。在这种情况下,这意味着要在您的上下文中查询具有这些ID的User实体。然后,在您的CreateMap中:

.ForMember(dest => dest.friends, opts => opts.ResolveUsing<FriendsResolver>());

但是,这仅涵盖关系的一侧,因此,如果您需要映射另一种方式,则可能还需要针对该路径的自定义解析器。在这里,我认为您实际上没有。您应该可以轻松解决:

.ForMember(dest => dest.friendsId, opts => opts.MapFrom(src => src.friends.Select(x => x.Id));

答案 1 :(得分:-1)

这会有所帮助

CreateMap<UserResource,User>()
    .ForMember(u => u.friends,opt => opt.MapFrom(t => new User {FriendsId = t.friendsId);

public class User
{
    ...
    public ICollection<User> friends { get; set; }
}

朋友在哪里ICollection<User>,而UserResource班级有ICollection<int>。这里有类型不匹配。您需要将ICollection映射到ICollection,这就是我强制投放new User ...

的原因