EF4问题/ MVC - 实体密钥,多对多关系等等。我错过了什么基本事实?

时间:2011-06-23 20:15:22

标签: c# asp.net-mvc-2 entity-framework-4

我一直在努力让EF4与MVC 2项目合作约六个月。这是一种折磨活动。尝试做任何非平凡的事情都需要玩杂耍的EntityKeys,做ObjectContext附加/分离舞蹈,并且,实际上,试图根据模糊的,几乎没有帮助的异常消息来实现必要的黑魔法。说它令人沮丧的是一个巨大而巨大的轻描淡写。

所以,放弃一边,这是我的问题:我有一个有点复杂的模型,我正在尝试通过表单创建/编辑。虽然大多数数据都是简单的标量,但也存在一些多对多数据。该网站将成为(如果我完成...)一个视频游戏评论网站。因此,多对多关系是游戏和它们可用的平台之间的关系(XBox 360,PS3等)。通过复选框选择平台,每个复选框与特定的平台ID相关联。

为了尝试以正确的方式做事,我在将数据传输到实际的Game和Platform实体之前绑定到编辑模型。传输数据后,我在我的存储库上调用我的Save方法,这实际上只是我的ObjectContext的包装器。

public void SaveGame(Game game)
{
    _siteDB.Games.Attach(game);

    if (game.GameID > 0)
    {
        _siteDB.ObjectStateManager.ChangeObjectState(game, System.Data.EntityState.Modified);
    }
    else
    {
        _siteDB.ObjectStateManager.ChangeObjectState(game, System.Data.EntityState.Added);
    }

    _siteDB.SaveChanges();
}

现在,我的Attach语句遇到了错误。离开它的地方,我得到一个异常,告诉我ObjectContext无法跟踪具有相同EntityKey的两个实体。如果我删除它,我会得到一个异常,告诉我游戏需要一个EntityKey。我尝试过使用ApplyCurrentValues,但是在尝试添加平台时遇到了类似的问题。

最终,似乎有一种特定的模式可以用来使这样的东西起作用。我似乎可以发现它是什么,而且非常令人沮丧。我只是看不到一个解决方案,它不需要我炸毁我的UI和后端之间的分离。

有人能指出我正确的方向吗?是否有任何MVC / EF4教程可以处理比着名的demoware示例更复杂的事情?


编辑:在以下方面取得了一些进展:

public void SaveGame(Game game)
{
    if (game.GameID > 0)
    {
        var editedGame = this.GetGame(game.GameID);

        var eSet = editedGame.EntityKey.EntitySetName;
        _siteDB.ApplyCurrentValues(eSet, game);

        var existingPlats = editedGame.Platforms.ToArray();

        foreach (var plat in existingPlats)
        {
            editedGame.Platforms.Remove(plat);
        }

        var newPlats = game.Platforms.ToArray();

        foreach (var nPlat in newPlats)
        {
            editedGame.Platforms.Add(nPlat);
        }

        game = null;

        _siteDB.ObjectStateManager.ChangeObjectState(editedGame, System.Data.EntityState.Modified);
    }
    else
    {
        _siteDB.Games.AddObject(game);
    }

    _siteDB.SaveChanges();
}

我现在唯一的问题是它将game添加到ObjectContext,即使我将其设置为null。所以,我的现有实体更新正常,但我也将一个新的镜像实体插入到数据库中。

1 个答案:

答案 0 :(得分:2)

问题是您在上下文中已经有Game具有相同ID。您不能拥有两个具有相同ID的对象。

如何进入该状态首先是您未显示的代码功能。但是,让我们谈谈解决你当前的问题。您可以采取两种方法:

  1. 分离现有对象,或
  2. 保留现有对象,并从新对象(作为参数传递的对象)复制值。
  3. 您可以选择适合您的那个,但这里的基本问题是您在内存中有两个不同的实例具有相同的GameID ,那很糟糕。