如何在不同的上下文中加载/修改/保存实体对象?

时间:2012-12-14 12:16:33

标签: c# entity-framework

使用实体框架(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();
}

2 个答案:

答案 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:

<强>型号:

enter image description here

我现在明白这个问题,我想。如何将实体附加到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);
            }

        }