繁体   English   中英

如何在 REST API 中发布多对多关系?

[英]How do you post a many-to-many-to-many relation in a REST API?

使用 EF 核心

我们正在尝试获取评估的所有信息,包括其组和所有分配的用户。 查看数据库图

什么按以下顺序工作;

  1. 空组的 HttpPost (api/Assessment/aID/groups) 到评估
  2. 用户到现有组的 HttpPost (api/Group/gID/users)

我们正在努力完成的事情(引用的代码是一个不同的例子,但原理相同)

  • HttpPost (api/Assessment/aID/groups) 其中组已包含用户列表。 尝试完成此操作时, a possible object cycle was detected which is not supported.
This piece of code is currently throwing a NullReference on Address
-------------------------------------------------------------------

   Group groupToCreate = new Group { Name = dto.Name, Description = dto.Description };

   foreach (var u in dto.Users)
   {
       groupToCreate.AddUser(new User
        {
             Name = u.Name,
             Email = u.Email,
             Address = new Address
             {
                 Country = u.Address.Country,
                 City = u.Address.City,
                 PostalCode = u.Address.PostalCode,
                 Street = u.Address.Street,
                 HouseNr = u.Address.HouseNr,
                 BusNr = u.Address.BusNr
             }
        });
    }

   _groupRepository.Add(groupToCreate);
   _groupRepository.SaveChanges();

   return groupToCreate;
  • HttpGet (api/Assessment),显示其分配的组和链接的用户。
This seems to be working
------------------------
   groupList = _groups.Select(g => new GroupDTO
   {
       Name = g.Name,
       Description = g.Description,
       Users = g.GroupUsers.Select(u => new UserDTO
       {
           Name = u.User.Name,
           Email = u.User.Email,
           Address = new AddressDTO
           {
              Country = u.User.Address.Country,
              City = u.User.Address.City,
              PostalCode = u.User.Address.PostalCode,
              Street = u.User.Address.Street,
              HouseNr = u.User.Address.HouseNr,
              BusNr = u.User.Address.BusNr
           }
       }).ToList()
   }).ToList();

参考:
用户
团体
评估
评估回购

很难说出您提供的详细信息,但我猜这是由于具有双向导航属性? 你在这里使用 EF 吗?

例如,如果您的 User 具有允许访问用户Group的 Navigation 属性,但是Group具有User对象的集合,那么每个用户都会自己在其中表达Group ...然后在尝试表达它时很容易陷入循环,例如用户看起来像:

{
  "Name":"user name",
  "Group":{
     "Name":"group1",
     "Users":[
       {
          "Name":"user name",
          "Group":{
            "Name":"group1",
            "Users":{
              ....
            }
          }
       }
     ]
  }
}

.. 因为一个User有一个GroupGroup有一个User对象列表,每个对象都有一个Group ...等等。

这是混合数据层和 DTO 对象所产生的问题。 更改您的系统,使您的 REST 方法返回的对象是为 API/前端的要求而设计的新对象。 这些对象可能看起来与您的数据库模型非常相似(至少最初是这样),但它们不应该是相同的对象。

创建没有任何逻辑或导航属性的全新对象,并且用于将信息传递回 API 消费者。 例如,一个简单的 class 给出用户组列表,这些组中的用户可以定义为:

public class UserDto
{
   public string UserName { get; set; }
   public IEnumerable<string> Groups { get; set; }
}

public class UserListDto
{
   public IEnumerable<UserDto> Users { get; set; }
}

然后您的 controller 操作可以执行以下操作:

var users = userService.GetAllUsers();

var result = new UserListDto { 
    Users = users.Select(u => new UserDto{
      UserName = u.Name,
      Groups = u.Groups.Select(g => g.Name)
      }
   };

return Ok(result);

..所以为响应序列化的东西没有任何复杂的关系需要协商,更重要的是改变你内部存储和处理数据的方式不会影响你的外部合同 API - API 消费者可以继续看到完全相同的信息,但存储和编译这些信息的方式可能会发生巨大变化。

人们很容易想到“我需要返回的数据与我在内部存储它的方式基本相同,所以只需重新使用这些类”,但这不是一个好主意,从长远来看只会带来问题。

为了避免不得不(重新)编写大量代码来将一个 object“转换”为另一个,我建议您研究类似 AutoMapper 的东西,因为这可以使它相当容易地重用并允许您将所有这些“翻译” ' 塞到一个地方。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM