Entity Framework Core POST 错误(无法转换 JSON 值)

Entity Framework Core POST error (JSON value could not be converted)

提问人:Waz 提问时间:11/16/2023 最后编辑:marc_sWaz 更新时间:11/16/2023 访问量:35

问:

我有以下实体:

public class Order 
{
    public int Id { get; set; }
    public string Name { get; set; }
    public OrderGroup OrderGroup { get; set; }
}

public class OrderGroup 
{
    public int Id { get; set; }
    public string Name { get; set }
    public Order Order { get; set; }
}

当我请求 时,我在 Swagger 中收到错误:POSTOrder

“订单”字段为必填项

JSON 值无法转换为 <API。Entities.Order> .路径:$。订单组.order |

这是有道理的,因为如果我在有效负载 () 中更改为 null,我能够修复错误。但是我需要它,所以可以选择有一个(所以我应该能够创建一个没有)。OrderGroup.orderOrderOrderGroupOrderOrderGroup

解决这个问题的最佳方法是什么?

是否有注释来处理这个问题,或者我会做这个客户端。我说注释,因为我还没有使用模型构建器。

这是一对一的关系。

我试过了:

  • 在有效负载上更改为 null 有效,但需要正确处理此问题
  • 也添加到 ,但仍然抛出相同的错误?OrderGroupOrder
.NET ASP.net-web-api 实体框架核心

评论


答:

1赞 Steve Py 11/16/2023 #1

避免此类问题的最简单建议是避免在服务器和客户端之间发送实体。

要使 POST 创建订单,请定义类似于 CreateOrderViewModel 的内容:

[Serializable]
public class CreateOrderViewModel
{
   public string Name { get; set; }
   public int? OrderGroupId { get; set; }
}

然后在控制器中:

[HttpPost]
public async Task CreateOrder(CreateOrderViewModel viewModel)
{
    ArgumentNullException.ThrowIfNull(viewModel, nameof(viewModel));

    OrderGroup? orderGroup = viewModel.OrderGroupId.HasValue 
        ? _context.OrderGroups.Single(x => x.Id == viewModel.OrderGroupId)
        : null;

    var newOrder = new Order
    { 
        Name = viewModel.Name,
        OrderGroup = orderGroup
    };
    _context.Orders.Add(newOrder);
    await _context.SaveChangesAsync();
}

这假定订单可能属于 OrderGroup,也可能不属于 OrderGroup。这不是一对一的关系,而是多对一的关系。许多订单可能与订单组相关联。Order 表将包含 OrderGroupId。通过使 OrderGroupId 为 null,订单不需要具有 OrderGroup 关联。一对一关系通常共享相同的 PK,但 EF 可以使用单独的 FK 强制实施一对一关系,例如具有唯一约束的多对一关系。

传递实体会给关联与创建带来许多问题,因为实体都将分离,并且上下文最终可能会以现有引用导致错误。当填充并从视图发送到控制器时,它们可能“看起来像”实体,但它们只是复制到实体类实例中的值。它们可能不完整,如果对它们使用类似的东西,则可能会使用不可信的值覆盖数据。实体也是一个重量级类别,需要发送循环引用等问题,并且通常包含比完成工作真正需要的更多的数据。Update

评论

0赞 Waz 11/17/2023
解决了我使用 DTO 的所有问题,但有两个问题:1) 最好为 POST 请求创建另一个 DTO 吗?所以现在我有两个 DTO,一个用于 GET,一个用于 POST。或者我应该在我的控制器方法中执行此操作。2) 外键默认为 0。我需要外键(例如,Order 不需要 OrderGroup)作为可选键,因此如果它们不输入任何内容,则应为 null。我在我的控制器中添加了一个 if 语句来检查它是否等于 0 并将其转换为 null。但这是最好的方法吗?
0赞 Steve Py 11/17/2023
如果您使用的是 FormPost,则通常 Get ViewModel 是在 Post 中提交的内容。如果你在非提交帖子中采用更多的 Ajax 方法,那么你可以创建一个专用的 DTO 或一个部分/全部填充的 Get VM。帖子只是参数化值,因此您的控制器方法可能只有命名参数,而不是 DTO 和实体,并且它可以正常工作。使用实体作为容器的问题在于,从视图发送的内容很少是完整的(如果你确实做到了,那就太过分了),不应该被信任作为实体附加和更新。
0赞 Waz 11/17/2023
干杯,测试了两个选项。拥有一个单独的 DTO 更干净,但同时考虑到 GET 和 POST 是相同的,除了一个不需要在 Post 中的导航属性之外,还有更多的维护。 一个 DTO 的第二个选项,然后在请求期间不填写它仍然让它出现在 Swagger 中,尽管我可以避免该对象。当然,从用户的角度来看,两者都有效!