使用Entity Framework更新异常?

3

你好,

我正在使用EntityFramework来开发我的ASP.NET MVC网站,但是在更新数据时遇到了一些问题。

这是我的更新代码:

using (BissEntities context = new BissEntities())
    {

      if (adCategoryFilter.Id < 1)
        context.AddToAdCategoryFilter(adCategoryFilter);
      else
        context.Refresh(System.Data.Objects.RefreshMode.ClientWins, adCategoryFilter);

      if (context.SaveChanges() > 0)
        return true;
    }
    return false;

执行context.Refresh时,我遇到了以下异常: 要刷新的对象集合中索引为0的元素具有空的EntityKey属性值或未连接到此ObjectStateManager。
Stacktrace :    at System.Data.Objects.ObjectContext.RefreshCheck(Dictionary`2 entities, Object entity, EntityKey key)
   at System.Data.Objects.ObjectContext.AddRefreshKey(Object entityLike, Dictionary`2 entities, Dictionary`2 currentKeys)
   at System.Data.Objects.ObjectContext.RefreshEntities(RefreshMode refreshMode, IEnumerable collection)
   at System.Data.Objects.ObjectContext.Refresh(RefreshMode refreshMode, Object entity)
   at Biss.Models.FilterModel.UpdateCategoryFilter(AdCategoryFilter adCategoryFilter) in C:\Users\Snowman\Documents\Visual Studio 2010\Projects\Biss\Biss\Models\FilterModel.cs:line 86 

这不是我第一次遇到这个问题了。起初我认为这可能与数据库中的关系有关,但在从受影响的表中删除这些内容后,相同的异常仍然存在。

adCategoryFilter来自哪里?

adCategoryFilter被实例化(new),然后用来自网站的ViewObject的数据填充。它确实具有所需的数据,如过滤器ID(将过滤器映射到正确的数据库行)。

请解释我为什么会遇到这个问题以及如何解决它。

最好的问候

2个回答

5

由于您使用的是ASP.NET MVC,因此您正在使用无状态环境。这意味着,一旦请求处理完成,就不再有“Entity Framework Memory”或“The Graph”。

因此,您需要明确告诉EF您希望添加或更新什么。

以下是操作步骤:

using (BissEntities context = new BissEntities())
{
  if (adCategoryFilter.Id < 1)
    context.AdCategoryFilters.AddObject(adCategoryFilter);
  else {
     var stub = new AdCategoryFilters { Id = adCategoryFilter.Id };
     context.AdCategoryFilters.Attach(stub);
     context.AdCategoryFilters.ApplyCurrentValues(adCategoryFilter);
  }

  context.SaveChanges();
}

那被称为“存根技术”。简而言之,您需要创建一个新实体,其实体键与要更新的实体相同(在您的情况下,实体键为“Id”)。然后,您“附加”此存根(使其由EF内部图跟踪),然后使用要更新的实体覆盖此存根上的值,最后保存更改。由于我采用了多层架构和使用POCO,自定义视图模型等,因此无法使用“UpdateModel”,因此我在我的服务/存储库上创建了一个自定义的“UpdateModel”方法 - 它执行了上述更复杂的版本。另外,请尽量不要在ASP.NET MVC中使用“if Id <1,则为添加”,因为如果您忘记在视图上绑定ID,则会将其传递为0,因此即使您正在进行更新,上面的代码也会尝试进行添加。 相反,要更明确,请为Add / Update拥有单独的操作方法。希望对你有所帮助。

4

不要使用刷新,尝试检索对象并使用类似于自动映射器(或MVC控制器中的UpdateModel)更新其属性。

EntityKey是一个单独的东西,与id属性有一些其他的操作。您新创建的对象缺少这些内容,这就是问题所在。

模式有点像(我不是C#专家,所以请原谅语法):

var context = new MyEntities();
var originalObject = context.MyObjectSet.Single(x => x.Id == viewmodel.Id);
UpdateModel(originalObject);
context.SaveChanges();

关键的区别在于,新检索到的对象已经正确设置了EntityKey。您可以有效地使用id属性来检测新/现有对象,但是EntityKey不仅仅是该属性。


谢谢,听起来不错。但是MVC中的UpdateModel和AutoMapper(http://automapper.codeplex.com/)有什么区别? - Banshee
不确定,我还没有查看它们的内部。我认为它们都使用反射并且非常相似,实际上我使用自己定制的版本,在元数据中明确标记要更新的属性。这两种方法的作用基本上是为您节省编写 origObject.Property = viewModel.Property 的每个属性的重复工作 - 尽管您可以这样做,它也同样有效。 - RichardW1001

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接