C# 实体框架核心在一对多关系中添加具有所需导航属性的新实体? 上下文
我正在做一个有C# 实体框架核心在一对多关系中添加具有所需导航属性的新实体? 上下文,c#,relationship,npgsql,nullable-reference-types,entity-framework-core-5,C#,Relationship,Npgsql,Nullable Reference Types,Entity Framework Core 5,我正在做一个有品牌s和oemodels的项目。它们之间存在一对多的关系。一个品牌可以有任意数量的oemodels,但是一个oemodel只能有一个品牌。出于业务原因,oemodels需要知道它们属于什么Brand 该项目使用Entity Framework Core 5.0和Npgsql 5.0.1包构建,以连接到PostgreSQL数据库。我使用代码优先的方法来生成数据库 此项目还使用可选的可空引用类型功能。这意味着任何指向引用类型的导航属性本质上都是[必需的],如下所示: 如果启用了可空引用
品牌
s和oemodel
s的项目。它们之间存在一对多的关系。一个品牌
可以有任意数量的oemodel
s,但是一个oemodel
只能有一个品牌。出于业务原因,oemodel
s需要知道它们属于什么Brand
该项目使用Entity Framework Core 5.0和Npgsql 5.0.1包构建,以连接到PostgreSQL数据库。我使用代码优先的方法来生成数据库
此项目还使用可选的可空引用类型功能。这意味着任何指向引用类型的导航属性本质上都是[必需的]
,如下所示:
如果启用了可空引用类型,则将根据其.NET类型的C#可空性配置属性:string?
将配置为可选,但string
将根据需要进行配置
这是我的数据库上下文类:
公共类AppDbContext:DbContext
{
公共AppDbContext(DbContextOptions:
作为一种更简洁的替代方法,可以在null原谅运算符(!)的帮助下简单地将属性初始化为null:
公共产品产品{get;set;}=null!;
除非由于编程错误(例如,未事先正确加载相关实体而访问导航属性),否则不会观察到实际的空值
我的问题
我目前在集成测试中将模型添加到现有品牌时遇到问题
假设以下代码已成功运行:
var firstBrand=新品牌{Name=“firstBrand”};
var secondBrand=新品牌{Name=“secondBrand”};
_context.Brands.Add(firstBrand);
_context.Brands.Add(secondBrand);
wait_context.SaveChangesAsync();
我无法为这些新创建的品牌添加型号:
var firstModel=新模型
{
Name=“FirstModel”,
OemNumber=“A-1”
};
var secondModel=新模型
{
Name=“SecondModel”,
OemNumber=“A-2”
};
var thirdModel=新模型
{
Name=“ThirdModel”,
OemNumber=“B-1”
};
firstBrand.OemModels.Add(firstModel);
firstBrand.OemModels.Add(secondModel);
第二品牌。OemModels.Add(第三品牌);
wait_context.SaveChangesAsync();
注意:上面的两个代码块采用相同的方法,它们之间没有任何代码
上述代码块失败,并显示以下错误消息:
Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while updating the entries. See the inner exception for details.
内部异常:
Npgsql.PostgresException
23505: duplicate key value violates unique constraint "PK_Brands"
at Npgsql.NpgsqlConnector.<ReadMessage>g__ReadMessageLong|194_0(NpgsqlConnector connector, Boolean async, DataRowLoadingMode dataRowLoadingMode, Boolean readingNotifications, Boolean isReadingPrependedMessage)
但它仍然失败,出现了同样的错误
我发现这令人困惑,因为我的数据库迁移为我的模型表生成了以下内容:
migrationBuilder.CreateTable(
名称:“Oemmodals”,
列:表=>new
{
Id=table.Column(类型:“integer”,可为空:false)
.Annotation(“Npgsql:ValueGenerationStrategy”,NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Name=table.Column(类型:“text”,可空:false),
OemNumber=table.Column(类型:“text”,可为空:false),
BrandId=table.Column(类型:“integer”,可为空:false)
},
约束:表=>
{
表.PrimaryKey(“PK_oemodels”,x=>x.Id);
表1.外键(
名称:“FK_Oemodels_Brands_BrandId”,
列:x=>x.BrandId,
原则:“品牌”,
主栏:“Id”,
onDelete:引用。级联);
});
以及:
migrationBuilder.CreateTable(
名称:“品牌”,
列:表=>new
{
Id=table.Column(类型:“integer”,可为空:false)
.Annotation(“Npgsql:ValueGenerationStrategy”,NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Name=table.Column(类型:“text”,可空:false)
},
约束:表=>
{
表.PrimaryKey(“PK_品牌”,x=>x.Id);
});
oemodel
表中没有“PK_Brands”,但当我试图保存向现有品牌添加oemodel
s时所做的更改时,会出现异常
在调试器中,我的两个品牌
s在添加到上下文后都具有唯一的Id
s(如我所料),因此在将oemodel
s添加到其内部列表时,它们都是独一无二的。我的理解是,如果我将它们添加到现有品牌并保存更改,那么这些模型应该自动生成它们的Id
s,不是吗
如果主要品牌
是[必选]的话,我对向现有品牌
s添加oemodel
s的正确方法有点困惑
属性。根据我的理解,null!
赋值应该允许我创建oemodel
s,而无需为其父品牌
直接添加到品牌
的oemodel
列表时指定导航属性,但我得到了“PK\u品牌”错误,无论是否定义了它们。编辑2
我猜你可能会说我有一个“大脑屁”。我已经有一段时间没有使用ASP.NET Core和EF Core了,完全忘记它不会自动跟踪基于分配的更改。你必须显式调用上下文。[EntityTypeHere].Update(EntityInstance)
将其标记为跟踪(这样下一次调用SaveChanges/async()
就可以了
而且,在hindsind中,“嗯,编辑1当然会起作用”。它在创建品牌的同时创建模型。它不会更新现有的品牌实体
简单的解决方法是:
firstBrand.OemModels.Add(firstModel);
firstBrand.OemModels.Add(secondModel);
第二品牌。OemModels.Add(第三品牌);
_context.Brands.UpdateRange(firstBrand,secondBrand);//这种方法是错误的。您使用了两个