EF Core - 已断开连接的已删除子项未删除

问题描述 投票:0回答:1

使用 EF Core 8,在新的数据库上下文中尝试删除 1:n 关系的子元素会失败。

在一个数据库上下文中,从 1:n 关系中删除一个子级是没有问题的,在 SaveChanges() 之后,该子级也会在数据库中删除。 例如:

using (var db = new BloggingContext())
{
    var blog = db.Blogs
        .Include(blog => blog.Posts)
        .FirstOrDefault(b => b.BlogId == blogId);

    if (blog != null)
    {
        blog.Url += $"/changed";
        if (blog.Posts.Count > 0)
        {
            // this one gets deleted - okay, we are in the same db context
            blog.Posts.Remove(blog.Posts[0]);
        }
        db.SaveChanges();
    }
}

但在断开连接的情况下不起作用。 在这里,我使用一个数据库上下文读取数据,更改值并尝试将更改后的值存储在第二个数据库上下文中。

在实际项目中,数据是通过Web-GUI读取的,然后更改的数据通过JSON传输,因此无法保持数据库上下文打开。

Blog? existingBlog = new();

using (var db = new BloggingContext())
{
    existingBlog = db.Blogs
        .Include(blog => blog.Posts)
        .FirstOrDefault(b => b.BlogId == blogId);
}

// change values, add Posts and delete Posts
Blog updatedBlog = ChangeValuesOfBlogAndPosts(existingBlog!);

// here we are in a new db context
using (var db = new BloggingContext())
{
    db.Blogs.Update(updatedBlog);
    db.SaveChanges();
}

现在,在 1-Side(此处:博客)中所做的所有更改均已保存,n-Side(= 帖子)中的所有更改均已保存,博客中的所有新帖子均已保存,但已删除的帖子仍在数据库中,所以在下次读取时我们仍然拥有所有已删除的数据。

我读过很多帖子,尝试了几种语法变体,我发现了“独立映射器”的提示,但我认为这是一个非常基本的功能,当我仅在一个数据库上下文中时它就可以工作,所以我担心我我只是缺少一件小事来让它在没有工具的情况下运行。

如果有任何重要意义,背后的数据库是 Oracle 19。

非常感谢您的帮助。

c# entity-framework-core
1个回答
0
投票

您无法那么简单地更新分离的对象图,而且在关联引用方面也会遇到问题。 (新的/更新的实体更改引用其他现有实体行与属于该实体下的集合/实例的关联。)

正如您所指出的,您无法在请求之间保持同一个 DbContext 实例打开。在单个请求中,EF 的更改跟踪将监视集合,以便在您删除项目时 EF 知道将其删除。当您分离并序列化该实体及其集合时,修改它,然后将其传递回另一个 DbContext,然后就没有更改跟踪。

Update 本质上是

Attach
DbContext 的一个实体,以开始跟踪从该时间点开始的更改。 EF 的文档很好地涵盖了这一点:(https://learn.microsoft.com/en-us/ef/core/ saving/disconnected-entities)向下滚动到“处理删除”和“新的和现有的混合”实体”。

本质上,在更新实体时,从数据库中获取实体(包括关联),然后确定需要插入、删除和更新哪些实体。这需要更多的工作,并且由于您无法真正依赖实体图,因此您可以考虑简化序列化为 JSON 的数据负载,然后再返回使用轻量级 DTO,而不是序列化实体。除了通过网络传输的数据包大小之外,另一个好处是,这有助于防止过度暴露服务的内部数据结构。

© www.soinside.com 2019 - 2024. All rights reserved.