简体   繁体   English

如何使用 Entity Framework + OData POST 多个相关实体?

[英]How to POST multiple related entities with Entity Framework + OData?

What is the proper way to POST multiple related entities and check required properties?发布多个相关实体并检查所需属性的正确方法是什么?

I have two entities Product and Package .我有两个实体ProductPackage A Product can have many Packages .一个Product可以有多个Packages A Package cannot exist without a related Product .没有相关Product Package就不能存在。

When I POST a new Product with a collection of multiple Packages , the ModelState says the model is invalid because the Packages do not have their required productId foreign key set.当我发布具有多个Packages集合的新Product时, ModelState表示模型无效,因为Packages没有所需的productId外键集。 This causes my API to return a BAD REQUEST status.这会导致我的 API 返回BAD REQUEST状态。

It's my understanding that Entity Framework supports this .我的理解是Entity Framework 支持这个 I would expect the ModelState to detect that the Package productId FK will be set automatically and thus wouldn't be invalid.我希望ModelState检测到 Package productId FK 将自动设置,因此不会无效。

If I remove the block of code that checks the ModelState validity Entity Framework behaves as expected and the Product and Packages are created.如果我删除检查ModelState有效性的代码块,实体框架会按预期运行,并且会创建ProductPackages

POST /api/v1/Products
BODY
{
   "name": "Coca-Cola",
   "packages": [
        {
            "count": 6,
            "quantity": 12,
            "quantityUnit": "oz"
        }
    ]
}

Here is my controller function:这是我的控制器功能:

[HttpPost]
[ODataRoute("")]
[EnableQuery]
public virtual async Task<IActionResult> PostEntity([FromBody] Product entityToCreate)
{
    //Removing this block will cause the request to succeed
    // but will also allow invalid requests to get to the database
    if (!ModelState.IsValid) 
    {
        return BadRequest(ModelState);
    }

    _context.Packages.Add(entityToCreate);
    await _context.SaveChangesAsync();

    return Created("DefaultApi", entityToCreate);
}

And here are my models:这是我的模型:

public class Product: ModelBase
{
    [Required]
    public string name { get; set; }

    public List<Package> packages { get; set; }
}

public class Package: ModelBase
{
    //some required props...

    [Required]
    [ForeignKey("product")]
    public Guid? productId { get; set; }
    public Product product { get; set; }
}

Some things I've investigated:我调查过的一些事情:

  1. Dropping the [Required] attribute on packageId and manually editing the db migration to include the constraint.删除packageId上的[Required]属性并手动编辑数据库迁移以包含约束。 This causes an error to be thrown later in the stack by the database.这会导致数据库稍后在堆栈中抛出错误。 I'd rather fail before getting to the database我宁愿在进入数据库之前失败

  2. Writing my own validation attributes.编写我自己的验证属性。 This seems unnecessary given that the EF documentation claims to support this鉴于 EF 文档声称支持这一点,这似乎没有必要

  3. Possibly using OData Batch Requests可能使用 OData 批量请求

I typically create a very specific "model" class (not an entity) to represent the payload of an HTTP Post (Put, Patch, etc.).我通常会创建一个非常具体的“模型”类(不是实体)来表示 HTTP Post(Put、Patch 等)的有效负载。 In this case you'd want a set of models.在这种情况下,您需要一组模型。 Then I have validation rules specific this set of models.然后我有特定于这组模型的验证规则。 Some call these models, DTOs, ViewModels, etc. The important thing is that they are not EF entities.有些人称这些模型为 DTO、ViewModel 等。重要的是它们不是 EF 实体。

After verifying their validity, you will have to map these models into the appropriate entities so they can be persisted with EF.在验证它们的有效性之后,您必须将这些模型映射到适当的实体中,以便它们可以通过 EF 进行持久化。 This mapping is the unfortunate tax of decoupling your entities from your exposed models.这种映射是将实体与公开模型分离的不幸税收。 You can do this manually or use a library like automapper .您可以手动执行此操作或使用automapper 之类的库。

There are many advantages to this strategy:这种策略有很多优点:

  • You can support several variations of manipulating your persisted Product/Package data without having to accommodate each of the variations with one set of entities.您可以支持操作持久产品/包数据的多种变体,而不必用一组实体来适应每个变体。 This means you can sensibly create and expose different sets of properties (models) with different validation rules for the same persisted data types (entities).这意味着您可以明智地为相同的持久化数据类型(实体)创建和公开具有不同验证规则的不同属性(模型)集。
  • You protect yourself from overposting .您可以保护自己免于过度发布 You don't want the user to be able to set the state of all properties without restriction.您不希望用户能够不受限制地设置所有属性的状态。
  • Your exposed endpoints (controller actions) have parameters that are decoupled from your entities.您公开的端点(控制器操作)具有与您的实体分离的参数。 This means that you can freely change the entities without necessarily having to change the exposed models that represent them and vice versa.这意味着您可以自由更改实体,而不必更改表示它们的公开模型,反之亦然。 You could hypothetically abandon EF altogether and move to some neat NoSQL persistence solution without having to change your expose APIs.假设您可以完全放弃 EF,转而使用一些简洁的 NoSQL 持久性解决方案,而无需更改您的公开 API。

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

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