sql-server - ASP.NET Core/Entity Framework - 使用多对多关系时,HTTP Post 不会在联接表中创建实体

标签 sql-server asp.net-mvc entity-framework entity-framework-core odata

  1. 我正在开发一个带有 SQL Server 数据库的 ASP.NET Core 7 MVC 应用。
  2. 我使用的是 EF Core 7 - 我的数据库表是通过 EF 迁移使用我当前的模型生成的。
  3. 我使用的是 OData 8 Controller
  4. 我正在关注 this关于在我的模型之间建立多对多关系的文档。我的理解是,我的模型是“传统”的,因此可以利用 EF 中的跳过导航。

我的模型:

namespace testapp.Models;

using System.ComponentModel.DataAnnotations;

public class Home
{
    [Key]
    public Guid Id { get; set; }

    public bool Active { get; set; }

    public string? Name { get; set; }

    public string? Description { get; set; }

    public double BaseCost { get; set; }

    public double BasePrice { get; set; }

    public List<Option> Option { get; } = new();

}

public class Option
{
    [Key]
    public Guid Id { get; set; }

    public bool Active { get; set; }

    public string? Name { get; set; }

    public string? Description { get; set; }

    public double Cost { get; set; }

    public double Price { get; set; }

    public List<Home> Home { get; } = new();

}

我的 Controller :

namespace testapp.Controllers;


using System.Collections.Generic;
using System.Linq;
using testapp.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.OData.Query;
using Microsoft.AspNetCore.OData.Routing.Controllers;

[EnableQuery]
public class HomeController : ODataController
{
    private readonly TestDbContext _context;

    private readonly ILogger<HomeController> _logger;

    public HomeController(ILogger<HomeController> logger, TestDbContext dbContext)
    {
        _logger = logger;
        _context = dbContext;
    }

    [HttpPost]
    public IActionResult Post([FromBody] Home HttpBody)
    {
        if (ModelState.IsValid)
        {
            _context.Home.Add(new Home()
            {
                Name = HttpBody.Name,
                BaseCost = HttpBody.BaseCost,
                BasePrice = HttpBody.BasePrice
            });
     

            _context.SaveChanges();
            return Ok();
        }
        else
        { 
            return BadRequest(); 
        }
    }
}

我的DbContext:

namespace testapp.Models;

using Microsoft.EntityFrameworkCore;


public class TestDbContext : DbContext
{

    public DbSet<Home> Home { get; set; }

    public DbSet<Option> Option { get; set; }

    public TestDbContext(DbContextOptions<TestDbContext> options) : base(options) { }

}

我的相关WebApplicationBuilder:

var modelBuilder = new ODataConventionModelBuilder();
//modelBuilder.EntityType<TestModel>();
modelBuilder.EntitySet<Home>("Home");
modelBuilder.EntitySet<Option>("Option");



builder.Services.AddControllers().AddOData(
    options => options.Select().Filter().OrderBy().Expand().Count().SetMaxTop(50).AddRouteComponents(
        routePrefix: "api",
        model: modelBuilder.GetEdmModel()).EnableAttributeRouting=false);

EF 迁移完成后,它在我的 SQL 数据库中创建了 3 个表 -“Home”、“Option”和“HomeOption”。我的理解是“HomeOption”是一个连接表,用于保存“Home”和“Option”的多对多关系。它唯一的列是“HomeId”和“OptionId”

当我发送包含新“Home”和现有“Option”内容的 HTTP Post 请求时,我希望连接表(“HomeOption”)中出现一个条目来指示两个实体之间的关系.

我尝试了 DbContext 的各种组合并手动指定连接类型,但没有取得任何成功。我开始怀疑我的 Controller 操作是否错误 - 是由我还是 EF 创建“HomeOption”实体? MS 在其知识库中的建议是让 EF 按惯例处理此问题,因此我希望在适用的情况下这样做。

作为引用,这是我的 POST 请求的正文:

{
    "Active": true,
    "Name": "5:58",
    "Description": null,
    "BaseCost": 9.99,
    "BasePrice": 29.99,
    "Option": [
        {
            "Id": "379ef6b2-b533-4e5e-8e67-08db77c67ccd",
            "Active": false,
            "Name": "chimney",
            "Description": null,
            "Cost": 0.0,
            "Price": 0.0
        }
    ]
}

最佳答案

新建了一个已添加到 DbContext 的 Home,而不是您通过 POST 传入的数据 block :

       _context.Home.Add(new Home()
        {
            Name = HttpBody.Name,
            BaseCost = HttpBody.BaseCost,
            BasePrice = HttpBody.BasePrice
        });

如果您绝对相信主页和选项是值得信赖的,并且只包含可以插入的数据(而不是对现有实体的引用),那么您可以使用:

_context.Home.Add(HttpBody);

这将添加提供的主页及其选项。

如果 Home 或 Option 持有对预计已存在于数据库中的另一个实体的引用,则这将不起作用。您将收到与插入重复 PK 相关的异常。在这些情况下,您需要识别已存在的任何内容,检查 DbContext 本地缓存中是否有任何跟踪的引用,用跟踪的实例替换引用,或者如果没有跟踪任何内容,则将引用的实体附加到保存 Home 之前的 DbContext。我刚刚在这里回答了有关该场景的问题:( Insert a List of complex objects without inserting navigational properties in Entity Framework )

关于sql-server - ASP.NET Core/Entity Framework - 使用多对多关系时,HTTP Post 不会在联接表中创建实体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76577311/

相关文章:

sql-server - 仅在一行会受影响的情况下如何执行UPDATE?

c# - 使用 EF 和 WebApi 将父/子对象序列化为

entity-framework - 在 EF Core 1.1 和 2.0 中使用相同的 EF 数据库路径

c# - 在托管和非托管代码之间共享数据库事务

sql-server - sql server在不匹配时合并多个插入

sql - SQL Server 2012 中的平均值和案例

sql - TSQL更新触发器: joining inserted and deleted

asp.net-mvc - 第二次请求后 TempData 不会销毁

.net - 对商业MVC控件的看法

asp.net-mvc - OwinStartup 未启动...为什么?