首页 > 解决方案 > EFCore 删除引用的实体

问题描述

我在一个项目中有两个实体:SupplierFinishingItemProductOptionListItem.

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

我在这里想念什么?

标签: c#entity-framework-core

解决方案


该问题是由集合导航​​属性的实现引起的:

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); // <--

推荐阅读