entity-framework - 实体框架 - 添加具有相关实体的实体时出错
问题描述
我有两个实体:
public class EntityA
{
public int? Id { get; set; }
public string Name { get; set; }
public EntityB { get; set; }
}
public class EntityB
{
public int? Id { get; set; }
public string Version { get; set; }
}
EntityB
我已经在数据库中有现有记录。我想EntityA
参考其中一条EntityB
记录添加一个新的。
var entityB = _dbContext.EntityB.FirstOrDefault(e => e.Id == 1);
var entityA = new EntityA { Name = "Test", EntityB = entityB };
_dbContext.Add(entityA);
_dbContext.SaveChanges();
当上面的代码运行时,我收到以下错误:
System.InvalidOperationException:实体类型“EntityB”上的属性“Id”是键的一部分,因此无法修改或标记为已修改。要使用标识外键更改现有实体的主体,首先删除依赖项并调用“SaveChanges”,然后将依赖项与新主体关联。
在我看来,保存也试图添加EntityB
,而不仅仅是对它的引用。我确实在数据库和实体框架中指定了关系,例如,当查询EntityA
我是否包含EntityB
在选择中时,我也得到了引用的实体(因此关系有效)。
modelBuilder.Entity<EntityA>(e =>
{
e.HasKey(p => p.Id);
e.HasOne(p => p.EntityB)
.WithOne()
.HasForeignKey<EntityB>(p => p.Id);
}
modelBuilder.Entity<EntityB>(e =>
{
e.HasKey(p => p.Id);
}
如何保存一个新EntityA
的,只引用选定的EntityB
,而不是保存两个实体?
解决方案
这会出错,因为您使用 EntityA 的 PK 作为 Entity B 的 FK,它强制执行 1 对 1 的直接关系。这方面的一个例子是有类似 Order 和 OrderDetails 的东西,其中包含有关特定订单的其他详细信息。两者都将使用“OrderId”作为他们的 PK,而 OrderDetails 使用它的 PK 与它的订单相关联。
相反,如果 EntityB 更像是 OrderType 引用,则不会使用 HasOne / WithOne 关系,因为这将要求 Order #1 仅与 OrderType #1 关联。如果您尝试将 OrderType #2 链接到 Order #1,EF 将尝试替换 OrderType 上的 PK,这是非法的。
通常,EntityA 和 EntityB 之间的关系需要 EntityA 表上的 EntityBId 列作为 FK。这可以是 EntityA 实体中的一个属性,或者保留为影子属性(推荐在 EntityA 将具有 EntityB 导航属性的情况下)使用上面带有 Order 和 OrderType 的示例,Order 记录将具有一个 OrderId (PK) 和一个 OrderTypeId ( FK) 到与其关联的订单类型。
对此的映射将是:(阴影属性)
modelBuilder.Entity<EntityA>(e =>
{
e.HasKey(p => p.Id);
e.HasOne(p => p.EntityB)
.WithMany()
.HasForeignKey("EntityBId");
}
一个 OrderType 可以分配给许多 Orders,但我们没有 OrderType 上的 Orders 集合。我们使用.HasForeignKey("EntityBId")
来在 EntityA 表上设置“EntityBId”的影子属性。或者,如果我们在 EntityA 上声明 EntityBId 属性:
modelBuilder.Entity<EntityA>(e =>
{
e.HasKey(p => p.Id);
e.HasOne(p => p.EntityB)
.WithMany()
.HasForeignKey(p => p.EntityBId);
}
附带说明一下,导航属性应该被声明virtual
。即使您不想依赖延迟加载(推荐),它也有助于确保完全支持用于更改跟踪的 EF 代理,并且延迟加载通常是在运行时比抛出 NullReferenceExceptions 更好的条件。
推荐阅读
- java - 如何使用 Java 从 Windows 获取 GPS 位置
- php - PHP 匹配 2 个字符串
- xamarin - LinkAssemblies 任务意外失败。- Xamarin.Forms (Android)
- xml - 错误:“文件过早结束。” 在jsp页面上
- c# - 我可以使用泛型类型参数作为返回类型吗?
- python-3.x - 过滤,替换python图中的组值
- python-3.x - 如何更改导出的默认数据类型?
- php - PHP登录系统不起作用
- python - 在 Pytest 中使用 excel 参数化测试
- javascript - TinyMCE 4.3 只上传一张图片