c# - EFCore 删除引用的实体
问题描述
我在一个项目中有两个实体:SupplierFinishingItem
和ProductOptionListItem
.
ProductOptionListItem
通过导航属性引用另一个。
当我尝试创建 1ProductOptionListItem
引用时,SupplierFinishingItem
它可以工作并将关系保存在数据库中。
但是,当我尝试创建 2 个或更多ProductOptionListItem
对相同的引用时,SupplierFinishingItem
只有第一个实体将关系保存到数据库中。其他的与null
参考一起保存。
我设法在最小的控制台应用程序中重现它:
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
namespace relationship_test
{
class Program
{
static void Main(string[] args)
{
using (var db = new DatabaseContext())
{
var finishing = new SupplierFinishingItem { Name = "Finishing"};
db.Finishings.Add(finishing);
db.SaveChanges();
db.Options.Add(new ProductOptionListItem { Name = "Option 1", SupplierFinishingItem = finishing });
db.Options.Add(new ProductOptionListItem { Name = "Option 2", SupplierFinishingItem = finishing });
db.Options.Add(new ProductOptionListItem { Name = "Option 3", SupplierFinishingItem = finishing });
db.SaveChanges();
}
}
}
public class DatabaseContext : DbContext
{
public DbSet<ProductOptionListItem> Options { get; set; }
public DbSet<SupplierFinishingItem> Finishings { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(
@"Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=entity-test;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<ProductOptionListItem>()
.HasOne(p => p.SupplierFinishingItem)
.WithMany(s => s.UsedBy)
.HasForeignKey(p => p.SupplierFinishingItemId)
.OnDelete(DeleteBehavior.Restrict);
}
}
public class ProductOptionListItem
{
public Guid Id { get; set; }
public string Name { get; set; }
public Guid? SupplierFinishingItemId { get; set; }
public SupplierFinishingItem SupplierFinishingItem { get; set; }
}
public class SupplierFinishingItem
{
private HashSet<ProductOptionListItem> _usedBy;
public Guid Id { get; set; }
public string Name { get; set; }
public IEnumerable<ProductOptionListItem> UsedBy => _usedBy?.ToList();
}
}
运行此代码后生成的数据库如下:
如您所见,只有Option 1
一个SupplierFinishingItemId
,其他两个是NULL
。
我在这里想念什么?
解决方案
该问题是由集合导航属性的实现引起的:
public IEnumerable<ProductOptionListItem> UsedBy => _usedBy?.ToList();
从 getter 返回新的列表实例会以某种方式混淆 EF Core 导航属性修复代码并产生上述效果(甚至在 `SaveChanges() 调用之前)。
解决方案是修复实现以在每次调用时不返回新列表(无论如何这对于属性获取器来说都是一种不好的做法),例如:
public IEnumerable<ProductOptionListItem> UsedBy => _usedBy ?? (_usedBy = new HashSet<ProductOptionListItem>());
或将 EF Core 配置为直接使用支持字段:
modelBuilder.Entity<ProductOptionListItem>()
.HasOne(p => p.SupplierFinishingItem)
.WithMany(s => s.UsedBy)
.HasForeignKey(p => p.SupplierFinishingItemId)
.OnDelete(DeleteBehavior.Restrict)
.Metadata.PrincipalToDependent.SetPropertyAccessMode(PropertyAccessMode.Field); // <--
推荐阅读
- reactjs - 无法从 api 加载帖子
- blueprism - Blue Prism 流程在通过 Process Studio 运行时使用哪个端口?
- pine-script - 如何根据 pinescript 中的条件找到关闭?
- javascript - 使用 Javascript 将对象添加到现有对象
- javascript - 卡塔:走十分钟
- javascript - 垂直滚动条未显示在用 javascript 填充的 html 表中
- cmake - Qt5 - MinGW64 - qResourceFeatureZlib() 入口点未找到
- docker - 有没有办法在 Kubernetes 集群上创建相互依赖的 pod?
- javascript - 如何从文件名 (PNG) 在 HTML 上制作日期
- sql - DB2 无法从内部查询中选择不同的列值