【发布时间】:2011-09-05 21:56:00
【问题描述】:
解释起来有点复杂,请多多包涵。
我有一个 ASP.NET MVC 2 项目正在慢慢杀死我,我正在尝试获取表单数据并将其转换为实体以创建或更新,具体取决于情况。最相关的部分(伪代码):
Entity Game
Scalar properties
EntityCollection<Platform> Platforms
基本的工作流程是:
表单数据 -> 模型绑定到 DTO -> 使用 AutoMapper 将 DTO 映射到 EF4 实体。
这一切都很好,但有一个例外 - 我需要使用 DTO 中包含的原始整数索引数据创建或更新游戏实体的平台 EntityCollection。所以,这是我一直在尝试的,但不起作用:
public AdminController(IArticleRepository articleRepository, IGameRepository gameRepository, INewsRepository newsRepository)
{
_articleRepository = articleRepository;
_gameRepository = gameRepository;
_newsRepository = newsRepository;
Mapper.CreateMap<AdminGameEditModel, Game>()
.BeforeMap((s, d) =>
{
if (d.Platforms.Count > 0)
{
Platform[] existing = d.Platforms.ToArray();
foreach (var plat in existing)
{
d.Platforms.Remove(plat);
}
}
foreach (var platId in s.PlatformIDs)
{
var newPlat = _gameRepository.GetPlatform(platId);
d.Platforms.Add(newPlat); // <-- where it chokes
}
})
.ForMember(dest => dest.BoxArtPath, opt => opt.Ignore())
.ForMember(dest => dest.IndexImagePath, opt => opt.Ignore())
.ForMember(dest => dest.Cons, opt => opt.MapFrom(src => String.Join("|", src.Cons)))
.ForMember(dest => dest.Pros, opt => opt.MapFrom(src => String.Join("|", src.Pros)))
.ForMember(dest => dest.LastModified, opt => opt.UseValue(DateTime.Now))
.ForMember(dest => dest.Platforms, opt => opt.Ignore());
}
具体来说,我在上面突出显示的行中遇到了一个异常:
无法定义两个对象之间的关系,因为它们附加到不同的 ObjectContext 对象。
一些研究告诉我这是意料之中的,因为我的新 Game 对象没有与之关联的 ObjectContext,并且 null 上下文被认为是一个单独的上下文。请参阅this brief explanation from Julie Lerman 了解更多信息。
好吧,作为一个勇敢的人,我想我可以简单地使用 ObjectContext 注册我的游戏,一切都会得到解决。所以,我尝试了:
Game game = new Game();
_gameRepository.RegisterGame(game);
RegisterGame 就是这样:
public void RegisterGame(Game game)
{
_siteDB.Games.AddObject(game);
}
不幸的是,这没有奏效。在同一点抛出相同的异常。
所以,看来我必须将每个平台的 EntityKey 添加到我的 EntityCollection 中。唯一的问题是,我不知道该怎么做。
那么,有什么想法吗?
编辑:某种进展。我尝试只添加平台实体的 EntityKey,如下所示:
Mapper.CreateMap<AdminGameEditModel, Game>()
.BeforeMap((s, d) =>
{
if (d.Platforms.Count > 0)
{
Platform[] existing = d.Platforms.ToArray();
foreach (var plat in existing)
{
d.Platforms.Remove(plat);
}
}
foreach (var platId in s.PlatformIDs)
{
var newPlat = _gameRepository.GetPlatform(platId);
d.Platforms.Add(new Platform { EntityKey = newPlat.EntityKey });
}
})
并且它消除了“两个不同的 ObjectContexts”异常。问题是,如果我尝试将新游戏实体添加或附加到我的上下文中,我会收到以下异常:
ObjectStateManager 中已存在具有相同键的对象。 ObjectStateManager 无法跟踪具有相同键的多个对象。
不幸的是,该异常没有指定 哪个 对象,但我敢打赌它是平台对象之一,因为它们已经存在,而我只是想建立一种新的关系两者之间。
所以,问题仍然存在:到底是如何创建一个新实体并使用现有实体填充其 EntityCollection 属性的?我不可能是唯一一个想要创建新实体并在它与现有实体之间创建新的多对多关系的人,对吧?
【问题讨论】:
-
嘿,这里是 VT ;) 如果您先检查一下,我将引用我在线程中所说的话:您的“GetPlatform”方法是否使用与您的“RegisterGame”方法使用相同的上下文?仔细检查这些方法,它们正在访问 exact 相同的 Context 实例(不是克隆,不是单独的实例,而是完全相同的实例)。哦,并确保您将新的 Game 对象添加到上下文中(即不要丢弃您为将其添加到上下文中所做的更改),您肯定希望它与上下文相关联。
-
是的,这是下一步。看起来它是相同的上下文,因为这两种方法都在访问同一个 repo,但这个例外让我感到奇怪。我正在学习如何创建一个上下文并将其与 Ninject 的所有存储库共享。
-
啊,但是特定方法的内部是否也使用相同的上下文实例?我可以看到一个场景,其中一个人可能不小心 - 例如 - 在“GetPlatform”方法中创建了一个新上下文。绝对检查它只是为了确定。要检查的另一件事是他们没有使用存储库本身的单独实例。两者都绝对值得一试!
-
当我有机会的时候肯定会检查它,虽然我有一个偷偷摸摸的怀疑,如果我确实有重复的上下文,它发生在 AutoMapper 本身。理想情况下,我会创建一个上下文,然后将其注入到我的存储库中,它们本身将被注入到我的控制器中。如果你想看一看,我也在想办法:stackoverflow.com/questions/6231851/…
标签: c# asp.net-mvc-2 entity-framework-4 automapper