使用 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。
非常感谢您的帮助。
您无法那么简单地更新分离的对象图,而且在关联引用方面也会遇到问题。 (新的/更新的实体更改引用其他现有实体行与属于该实体下的集合/实例的关联。)
正如您所指出的,您无法在请求之间保持同一个 DbContext 实例打开。在单个请求中,EF 的更改跟踪将监视集合,以便在您删除项目时 EF 知道将其删除。当您分离并序列化该实体及其集合时,修改它,然后将其传递回另一个 DbContext,然后就没有更改跟踪。
Update 本质上是
Attach
DbContext 的一个实体,以开始跟踪从该时间点开始的更改。 EF 的文档很好地涵盖了这一点:(https://learn.microsoft.com/en-us/ef/core/ saving/disconnected-entities)向下滚动到“处理删除”和“新的和现有的混合”实体”。
本质上,在更新实体时,从数据库中获取实体(包括关联),然后确定需要插入、删除和更新哪些实体。这需要更多的工作,并且由于您无法真正依赖实体图,因此您可以考虑简化序列化为 JSON 的数据负载,然后再返回使用轻量级 DTO,而不是序列化实体。除了通过网络传输的数据包大小之外,另一个好处是,这有助于防止过度暴露服务的内部数据结构。