2010-05-07 87 views
15

我在我的EF上下文中有IssuesScopes之间的多对多关系。在ASP.NET MVC中,我创建了一个Edit窗体,允许用户编辑特定的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); 
       } 
      } 

所以,当我试图在逻辑添加到保存相关领域,我试过几件事情,但最终,这是什么做的最有意义的对我说:

  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); 
       } 
      } 

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

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

我在做什么错?

回答

12

存根通常只对1-*关系有效。 *-*关系引入了一系列不同的挑战。

即是说,当你附加两端 - 不像1-* - 你仍然不知道关系是否已经存在或不存在。

因此,这意味着,该代码:

if (issue.Scopes.Contains(thisScope)) 

很可能将假每次都返回。

我会做的是这样的:

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. 

现在,你需要找出你需要添加&从问题中移除什么。作用域。 您可以通过比较基于ID来做到这一点。

即,如果您有一组要具有相关的问题(relatedScopes)

然后,代码使用的是哪种添加和怎样去除范围的ID。

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

现在对于TOADD你这样做:

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

并为每个需要删除

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

现在应该形成正确的关系范围。

希望这有助于

Alex

微软

+1

这很完美!看着SQL事件探查器,对于.Load()来说,这只是一个“额外”的数据库调用,但是与我过去用存储过程手动执行的方式相比,添加/删除更加简洁。谢谢! – Jorin 2010-05-13 06:10:17

+0

詹姆斯很好的答案。这是许多应用程序中的常见问题(有效添加/删除标签)。系统级功能是不是没有充满代码的屏幕?像* issue.Scopes.ReplaceWith(myScopes); * – TFD 2010-05-13 11:00:41

+0

@ TFD是的,我听到你。如果不这样做,英孚团队有很多东西,一个简单的扩展方法可以做到这一点,虽然正确吗? – 2010-05-14 00:52:56

0

警告,这只是从我的头顶开始,我没有尝试过。

我不认为你可以像使用ProjectID一样设置外键。

您需要检索项目并将其添加到scope.Project导航属性中。 EF将在您插入时处理关系。

现在,我没有尝试,可能是错的,但值得一试。也许这有助于你的方式..

+0

不,不这么认为。我只是将'thisScope.ProjectID = formIssue.ProjectID;'行更改为'thisScope.Project = issue.Project;'并且仍然有相同的错误。这是你的意思吗? – Jorin 2010-05-07 15:44:59

+0

好的,如果你没有自己解决问题,我会自己试试并发布我提出的代码。 – 2010-05-08 05:46:38

+0

不,我已经用尽了自己尝试不同的选择。在我的测试案例中,我有3个范围,其中2个已经与此问题相关联。我做到了这一点,所以我的表单上都检查了3个,所以2个现有的应该更新,1个应该与问题相关联。根据我的尝试,我得到了不同的结果,但没有做到它应该做的。奇怪的是,使用'.Add'方法,有时它会尝试向数据库添加一个新的作用域,而不是仅仅“添加”一个与此问题有关的新关联,但我无法理解如何让它正常工作。 – Jorin 2010-05-08 20:42:47

0

**免责声明:我是相对较新的EF,用一桶盐我的答案。

如果这是一个编辑表单,我认为您的问题对象不应该是一个“新”问题,它应该将问题拉出数据存储。据我所知可以看到:

Issue issue = new Issue { IssueID = id, TSColumn = formIssue.TSColumn }; edmx.Issues.Attach(issue); 你正在有效地创建一个新的问题与您试图编辑的ID。

再次,我在这里寻找方法来让EF自己有意义。有时候我会想念我的SQL语句。

+0

谢谢,但没有。就像我说的那样,它的问题部分工作正常,它只是我不能更新的子实体。你看到的“新”只是一种创建存根实体的方法,而不是使用EntityKey。看到这篇文章:http://blogs.msdn.com/alexj/archive/2009/06/19/tip-26-how-to-avoid-database-queries-using-stub-entities.aspx – Jorin 2010-05-08 04:08:36

+1

Ooohhh漂亮!我将不得不尝试这个存根实体的东西,它会减少很多不必要的查询。谢谢! – 2010-05-08 18:51:47