c# - EFCore 删除引用的实体

标签 c# entity-framework-core

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

ProductOptionListItem 通过导航属性引用另一个。

当我尝试创建 1 个引用 SupplierFinishingItemProductOptionListItem 时,它起作用并将关系保存在数据库中。

但是当我尝试创建 2 个或更多引用相同 SupplierFinishingItemProductOptionListItem 时,只有第一个实体将关系保存到数据库中。其他的保存为 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();
    }
}

运行此代码后生成的数据库如下:

enter image description here

如您所见,只有选项 1 有一个 SupplierFinishingItemId,其他两个都是 NULL

我在这里错过了什么?

最佳答案

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

public IEnumerable<ProductOptionListItem> UsedBy => _usedBy?.ToList();

从 getter 返回新的列表实例会以某种方式混淆 EF Core 导航属性修复代码并产生上述效果(甚至在调用 SaveChanges() 之前)。

解决方案是修复实现,使其在每次调用时不返回新列表(无论如何这被认为是属性 getter 的不良做法),例如:

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

关于c# - EFCore 删除引用的实体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55938310/

相关文章:

c# - 如何从pdf图像中查找文本?

c# - 通过属性或 setter 方法的 ASP.NET Core MVC 依赖注入(inject)

c# - IL 程序无效,我做错了什么? (简单的 if-else 代码)

entity-framework-core - Entity Framework 7 为模型构建器设置小数精度

c# - .ThenInclude 用于 Entity Framework Core 2 中的子实体

c# - 如何查询一个域的用户是否是另一个AD域中的组的成员?

c# - 将 Windows 应用商店应用程序中的 Canvas 保存为图像文件

c# - 找到多个 DbContext

c# - 如何在 EF core 2.1 中使用 FreeText

c# - 内存中的 EF Core SQLite 异常 : SQLite Error 1: 'near "MAX": syntax error'