与子实体(添加/更新必要)沿实体框架更新实体 [英] Entity Framework Update Entity along with child entities (add/update as necessary)

查看:124
本文介绍了与子实体(添加/更新必要)沿实体框架更新实体的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在我的EF上下文问题作用域之间的许多一对多的关系。在ASP.NET MVC中,我提出了一个编辑表单,允许用户编辑特定的问题。在窗体的底部,是复选框,允许他们选择的作用域适用于这一问题的列表。当编辑的问题,它可能会永远有它已经相关的一些作用域 - 这些箱子将已签。然而,用户有机会检查多个范围或删除某些检查当前作用域。我的code看起来像这样保存的只是问题

I have a many-to-many relationship between Issues and Scopes in my EF Context. In ASP.NET MVC, I bring up an Edit form that allows the user to edit a particular Issue. At the bottom of the form, is a list of checkboxes that allow them to select which scopes apply to this issue. When editing an issue, it likely will always have some Scopes associated with it already--these boxes will be checked already. However, the user has the opportunity to check more scopes or remove some of the currently checked scopes. My code looked something like this to save just the Issue:

            using (var edmx = new MayflyEntities())
            {
                Issue issue = new Issue { IssueID = id, TSColumn = formIssue.TSColumn };
                edmx.Issues.Attach(issue);

                UpdateModel(issue);

                if (ModelState.IsValid)
                {
                    //if (edmx.SaveChanges() != 1) throw new Exception("Unknown error. Please try again.");
                    edmx.SaveChanges();
                    TempData["message"] = string.Format("Issue #{0} successfully modified.", id);
                }
            }

所以,当我试着在逻辑添加到保存相关的范围,我试过几件事情,但最终,这是最有意义对我说:

So, when I try to add in the logic to save the associated scopes, I tried several things, but ultimately, this is what made the most sense to me:

            using (var edmx = new MayflyEntities())
            {
                Issue issue = new Issue { IssueID = id, TSColumn = formIssue.TSColumn };
                edmx.Issues.Attach(issue);

                UpdateModel(issue);

                foreach (int scopeID in formIssue.ScopeIDs)
                {
                    var thisScope = new Scope { ID = scopeID };
                    edmx.Scopes.Attach(thisScope);
                    thisScope.ProjectID = formIssue.ProjectID;
                    if (issue.Scopes.Contains(thisScope))
                    {
                        issue.Scopes.Attach(thisScope); //the scope already exists
                    }
                    else
                    {
                        issue.Scopes.Add(thisScope); // the scope needs to be added
                    }
                }

                if (ModelState.IsValid)
                {
                    //if (edmx.SaveChanges() != 1) throw new Exception("Unknown error. Please try again.");
                    edmx.SaveChanges();
                    TempData["message"] = string.Format("Issue #{0} successfully modified.", id);
                }
            }

但不幸的是,这只是抛出以下异常:

But, unfortunately, that just throws the following exception:

An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key.

我在做什么错了?

What am I doing wrong?

推荐答案

存根,一般只对有效1 - * 的关系。
。* - * 关系,引进了不同的挑战

Stubs are generally only effective for 1-* relationships. *-* relationships introduce a different set of challenges.

也就是说,当你连接两端 - 不像 1 - * - 你仍然不知道如果关系已经存在与否

Namely that when you attach both ends - unlike 1-* - you still have no idea if the relationship already exists or not.

因此​​,这意味着,这code:

So that means that this code:

if (issue.Scopes.Contains(thisScope))

大概是要假每次都返回。

Is probably going to return false every time.

我会做的是这样的:

edmx.Issues.Attach(issue);
UpdateModel(issue);
// or ctx.LoadProperty(issue, "Scopes") if it is a POCO class.
issue.Scopes.Load(); // hit the database to load the current state.

现在,你需要找出你需要添加和放什么;从issue.Scopes删除。
您可以通过基于ID比较做到这一点。

Now you need to find out what you need to add & remove from issue.Scopes. You can do this by comparing based on ID.

即。如果你有一组范围的ID,你希望有相关的问题(relatedScopes)

i.e. if you have a set of Scope IDs you want to have related to the issue (relatedScopes)

那么这code使用的是哪种添加什么移除。

Then this code works out what to add and what to remove.

int[] toAdd = relatedScopes.Except(issue.Scopes.Select(s => s.ID)).ToArray();
int[] toRemove = issue.Scopes.Select(s => s.ID).Except(relatedScopes).ToArray();

现在的TOADD你这样做:

Now for toAdd you do this:

foreach(int id in toAdd)
{
   var scope = new Scope{Id = id};
   edmx.Scopes.Attach(scope);
   issue.Scopes.Add(scope);
}

和每个作用域,你需要删除

And for each scope you need to remove

foreach(int id in toRemove)
{
   issue.Scopes.Remove(issue.Scopes.Single(s => s.ID == id));
}

现在正确的关系,应形成。

By now the correct relationships should be formed.

希望这有助于

亚历

微软

这篇关于与子实体(添加/更新必要)沿实体框架更新实体的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆