有以下两个实体:
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public CompanyVehicle CompanyVehicle { get; set; }
}
以及
public class CompanyVehicle
{
public int Id { get; set; }
public string Name { get; set; }
public Employee Employee { get; set; }
}
在SQL Server 2019
上使用Entity Framework Core 5.0.8
,CompanyVehicle的配置为:
entityBuilder.HasOne(t => t.Employee)
.WithOne(t => t.CompanyVehicle)
.HasForeignKey<Employee>(t => t.Id)
.IsRequired();
我们试着插入一些东西:
public void Create(Employee employee)
{
employee.CompanyVehicle = new CompanyVehicle();
dbContext.Add<Employee>(employee);
dbContext.SaveChanges();
}
上面的代码在EF6
中运行良好。Employee和CompanyVehicle表中的两条新记录是使用相同的Id
创建的。迁移到EF Core 5.0.8
后,dbContext.SaveChanges()抛出异常:
系统操作无效异常:尝试保存更改时,"Employee.Id"的值未知。这是因为该属性也是外键的一部分,而该外键在关系中的主体实体未知。
请注意,这些实体只是示例,在我的示例中不应更改数据库设计。
- 更新**
经过一番调查,我发现我的问题是:
将X
(主要)和Y
(从属)作为两个表,其中X.Id
是X
的PK,Y.Id
是Y
的PK,并且FK至X
,在EF Core中无法插入X
的记录。
4条答案
按热度按时间zvokhttg1#
所以我终于找到了问题所在,配置一个属性为
PK
和FK
是可能的,而且非常容易。我们在程序集中从EF6
迁移到EFCore
后有了旧代码。项目是一个框架,因此在OnModelCreating
中,我们使用基本DbContext
中的modelBuilder.ApplyConfigurationsFromAssembly
在客户项目中注册配置。项目将自动查找项目引用的所有程序集中的所有配置或应用程序路径中的DLL。关键在于:在
EF Core
中,FK
的显式配置与EF6
的相反,因此在EF6
中,对于Employee
,我们可以写:在
EF Core
中我们应该写:第一部分中使用的参数
d
的类型为CompanyVehicle
,因此我们的迁移程序将旧代码转换为:这是不正确的。泛型参数应该是依赖表类型。我们后来在一个新的命名空间中修复了这个问题,但是
ApplyConfigurationsFromAssembly
方法在我们配置之后也继续应用过时的代码。我在
OnModelCreating
末尾使用了以下代码块来调查这个问题:并注意到为我的实体配置了重复的密钥。
nkkqxpd92#
实体框架核心通过能够检测外键属性来配置一对一关系,从而识别关系中的主体和从属实体。
首先查看现有的数据库并检查依赖表是什么,假设它是
Employee
,它应该有一个指向CompanyVehicle
表的foriegn键(在您的情况下可能是相反的)。如果
Employee
是从属表,则将该foriegn键属性名(假设为Vehicle_Id
)添加到Employee
实体。如果不想向类添加属性,请按照第二种方法操作。如前所述,如果没有这个属性,就无法为一对一关系确定子/依赖方。(检查数据库中的内容并添加该属性,否则将在
Employee
表中获得两个外键)使用Fluent API,像这样配置关系。(注意如何使用a和b分隔两个导航属性,在您的实现中,您使用t分隔两个导航属性,当您使用
.HasForeignKey<Employee>(t => t.Id)
时,您将foriegn键设置为Employee
表的主键Id
,这可能是错误背后的原因)。如果你不想在依赖表中添加一个属性,使用数据库中现有的foriegn键(假设它是
Vehicle_Id
),fluent API配置应该如下所示。Has/With
模式用于闭合循环并完全定义关系。在这种情况下,由于要配置的关系是一对一的,因此HasOne
方法与WithOne
方法链接在一起。(Employee
)是通过将其作为类型参数传递给HasForeignKey
方法来标识的,HasForeignKey
方法接受一个lambda,该lambda指定依赖类型中的哪个属性是外键。因此,如果您希望
Employee Id
充当CompanyVehicle
表的foriegn键,请将Fluent API修改为:在指定lambda时再次注意a和b。elcex8rz3#
我和A·莫雷尔有同样的问题。
当手动插入ManyToMany的自定义连接表,并且外键为0时,我得到了这个错误。
通过将父表的种子值更改为从2:
因为这个问题
DBCC CHECKIDENT Sets Identity to 0
jfgube3f4#
对我来说,这似乎是由于创建了“空白”实体,我没有添加到上下文中。在EF6中,这些实体被忽略,因为它们没有添加,但在EF Core中,它们似乎是自动添加的。
我纠正了这个问题,将“可写”上下文的范围缩小到只有进行更改的那一行,并对其他所有内容使用单独的“只读”上下文。
我可以通过不在视图中直接使用实体类型来进一步纠正这一点,这样我就可以创建不是实体的空白条目。