- 我正在开发一个带有 SQL Server 数据库的 ASP.NET Core 7 MVC 应用。
- 我使用的是 EF Core 7 - 我的数据库表是通过 EF 迁移使用我当前的模型生成的。
- 我使用的是 OData 8 Controller
- 我正在关注 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/