Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 实体框架核心在一对多关系中添加具有所需导航属性的新实体? 上下文_C#_Relationship_Npgsql_Nullable Reference Types_Entity Framework Core 5 - Fatal编程技术网

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);//这种方法是错误的。您使用了两个