c# - Entity Framework 硬级联删除

标签 c# entity-framework sqlite

我有一个与 Entity Framework 映射的 SQLite 数据库。 有 2 个表:Collections (1:n) Albums。

当我删除一个集合时,所有相关的相册也必须被删除。 我使用 CollectionRepo.Delete(collection); 来实现这一点。它使用以下代码:

public int Delete(Collection entity)
{
    Context.Entry(entity).State = EntityState.Deleted;
    return Context.SaveChanges();
}

问题是:当我执行这段代码时,Context.SaveChanges(); 给我一个异常:

The operation failed: The relationship could not be changed because one or more of the foreign-key properties is non-nullable. When a change is made to a relationship, the related foreign-key property is set to a null value. If the foreign-key does not support null values, a new relationship must be defined, the foreign-key property must be assigned another non-null value, or the unrelated object must be deleted.

似乎 Entity Framework 想要在外键上 null 而不是删除条目。但这绝对不是我想要的,因为没有 parent 的相册毫无意义(至少在我的用例中)。

我显然可以先手动删除相册,然后再删除空的集合,但在我看来这有点棘手。首先,在我看来,EF 应该足够聪明,可以自己完成它以简化代码;其次,如果我有几十个与收藏和相册的关系,我最终会得到一个相当大、难以维护的关系,代码库。


集合类

public class Collection
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public long Id { get; set; }

    public virtual List<Album> Albums { get; set; } = new List<Album>();
}

专辑类

public class Album
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public long Id { get; set; }

    [Required]
    [ForeignKey("Collection")]
    public long CollectionId { get; set; }

    public virtual Collection Collection { get; set; }
}

DbContext 子类

public class DataEntities : DbContext
{
    public virtual DbSet<Collection> Collections { get; set; }
    public virtual DbSet<Album> Albums { get; set; }

    public DataEntities() : base("name=Connection")
    {
        Configuration.ProxyCreationEnabled = false;
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Album>()
            .HasRequired(a => a.Collection)
            .WithMany(c => c.Albums)
            .HasForeignKey(a => a.CollectionId)
            .WillCascadeOnDelete(true);
        modelBuilder.Entity<Collection>()
            .HasMany(c => c.Albums)
            .WithRequired(a => a.Collection)
            .WillCascadeOnDelete(true);
    }
}

最佳答案

应用分离对象图修改在 EF 中一直不清楚。这是无故失败的情况之一。

假设 Collection传递给 Delete 的实体方法有Albums集合填充(至少这是我能够重现异常的方式)。线路

Context.Entry(entity).State = EntityState.Deleted;

做两件事:附加 entity和所有 Album来自 entity.Albums 的对象根据上下文,标记 entity作为Deleted ,和(注意!)Album对象为 Modified .当您调用 SaveChanges 时,这会导致不正确的行为,最后生成有问题的异常。

有两种方法(变通方法)可以修复这种不正确的行为。

第一个是将上面一行替换为

Context.Collections.Attach(entity);
Context.Collections.Remove(entity);

效果与上述类似,重要和不同之处在于现在相关的Album标记为 Deleted 的对象, 这允许成功执行 SaveChanges .

缺点是现在 SaveChanges问题 DELETE每个 Album 的命令在删除 Collection 的命令之前,这是低效的并且没有多大意义,因为级联删除将在数据库内完美地处理它。

第二个选项是保持代码不变,但在附加实体之前清除相关集合:

entity.Albums = null;
Context.Entry(entity).State = EntityState.Deleted;

这允许成功执行 SaveChanges并生成一个 DELETE仅针对实体的命令。

缺点是您需要编写额外的代码并且不要忘记任何支持级联删除的子集合,而不是为需要级联更新的集合执行此操作(即具有可选关系,需要使用 NULL 更新 FK 字段) .

选择权在你。

关于c# - Entity Framework 硬级联删除,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41858097/

相关文章:

entity-framework - Azure 函数和空间类型以及程序集 'Microsoft.SqlServer.Types'

c - C中空表中的SQLite列名

c# - 更改 DocumentCompleted 中 Web 浏览器控件的大小

c# - IEnumerable 项目消失 - 存在于 DAL 但不存在于调用者中

c# - Entity Framework 错误 "You have an error in your sql syntax entity framework"

android - 获取 Room Persistence Library Android 的 onUpgrade() 回调

sqlite - 此Sqlite列使用什么时间戳格式?

c# - 什么是堆栈跟踪?

c# - 如何从正在运行的 WCF 服务中导出元数据

c# - 在 C# 中用常量乘/加大量数字的高性能方法是什么?