使用实体框架(EF)我想从我的数据库加载一个对象,修改它并保存回来。但是,加载和保存在不同的上下文中发生,我通过向对象的collection属性添加另一个对象来修改它。
根据MSDN中的famous blog/posts example考虑以下代码:
Blog blog;
using (BloggingContext db = new BloggingContext())
{
blog = db.Blogs.Include("Posts").Single();
}
// No one else knows the `post` object directly.
{
Post post = new Post {Blog = blog, Title = "Title", Content = "Content"};
blog.Posts.Add(post);
}
using (BloggingContext db = new BloggingContext())
{
// No idea what I have to do before saving...
// Can't do anything with `post` here, since this part will not know this
// object directly.
//db.Blogs.Attach(blog); // throws an InvalidOperationException
db.SaveChanges();
}
在我的数据库中,我有1个Blog
个对象,其中包含100个Post
个。如您所见,我想向此Post
添加新的Blog
。不幸的是,在保存之前执行db.Blogs.Attach(blog);
会抛出InvalidOperationException
说:“发生了参照完整性约束违规:定义参照约束的属性值在关系中的主体和从属对象之间不一致。“
让EF更新此博客需要做些什么?
更新
我认为我想要实现的目标(将实体的数据库更新与修改及其相关的子实体分离)是不可能的。相反,我认为现在相反的方向更可行:将子实体的更新/创建与其父实体分离。这可以通过以下方式完成:
Blog blog;
using (BloggingContext db = new BloggingContext())
{
blog = db.Blogs.Single();
}
Post post = new Post {BlogId = blog.BlogId, Title = "Title", Content = "..."};
using (BloggingContext db = new BloggingContext())
{
db.Posts.Add(post);
db.SaveChanges();
}
答案 0 :(得分:2)
您必须将实体附加到上下文,然后更改跟踪应该启动并保存更改将完成剩下的工作。
供参考:MSDN Attach Entities to Context
或者尝试显式添加它并直接设置关系所需的信息,而不是通过导航属性,如下所示:
Blog blog;
using (BloggingContext db = new BloggingContext())
{
blog = db.Blogs.Include("Posts").Single();
Post post = new Post {Blog = blog, Title = "Title", Content = "Content"};
post.blogId = blog.Id;
db.Posts.Add(post);
db.SaveChanges();
}
答案 1 :(得分:2)
编辑3:
<强>型号:强>
我现在明白这个问题,我想。如何将实体附加到db上下文并正确设置其状态。
您的问题是,在附加博客实例时,它包含一系列新帖和现有帖子。解决方案是首先附加博客实例的浅表副本(没有填充的帖子集合),然后添加新帖子。您也可以将现有实例加载到更改跟踪器中,但这会导致向数据库的往返,并会吸引一些批评者加入该聚会。
b.t.w。我首先使用正确版本的EF,然后在添加更正代码之前重现您的问题。
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
Blog blog;
private void fetchBlogData_Click(object sender, EventArgs e) {
using (var db = new StackOverflowEntities()) {
blog = db.Set<Blog>().Include("Posts")
.FirstOrDefault();
}
}
private void commitAllPosts_Click(object sender, EventArgs e) {
using (var db = new StackOverflowEntities()) {
// load existing blog into ChangeTracker (but not efficient)
// var existingBlog = db.Set<Blog>().First(b => b.BlogId == blog.BlogId);
// make shallow copy of existing blog and attach it
Blog existingBlog = new Blog {
BlogId = blog.BlogId,
Name = blog.Name
};
db.Set<Blog>().Attach(existingBlog);
// if the root blog record must be updated
//db.Entry(existingBlog).State == EntityState.Modified;
// add new posts to tracked Blog entity
foreach (var post in blog.Posts) {
if (post.PostId == 0) {
existingBlog.Posts.Add(post);
}
}
db.SaveChanges();
}
}
private void createArbPosts_Click(object sender, EventArgs e) {
var post = new Post {
Text = "Today I read but never understood a StackOverflow question.... again."
};
blog.Posts.Add(post);
var postPS = new Post {
Text = "Actually, i'm not sure i understand it yet."
};
blog.Posts.Add(postPS);
}
}