【问题标题】:Strongly-Typed ASP.NET MVC with Entity Framework具有实体框架的强类型 ASP.NET MVC
【发布时间】:2009-05-22 20:04:39
【问题描述】:

此代码无法实际保存任何更改:

//
// POST: /SomeType/Edit/5

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(Guid id, SomeType Model)
{
    db.AttachTo(Model.GetType().Name, Model);
    db.ApplyPropertyChanges(Model.EntityKey.EntitySetName, Model);
    db.SaveChanges();
    return RedirectToAction("Index");
}

ASP.NET MVC 将对象模型创建为 Department 类型的 EntityObject,EntityState 值为 Detached

使用AttachTo方法后,其EntityState变为Unchanged

MSDN on Attaching Objects (Entity Framework)

对象附加到对象 未更改状态的上下文。

由于它的 Unchanged 状态,ApplyPropertyChanges 方法什么都不做。

我希望它改为具有状态 Modified

MSDN on EntityState Enumeration

独立
对象存在但未被对象跟踪 服务。实体处于此状态 创建后立即 在它被添加到对象之前 语境。一个实体也在这个 删除后的状态 通过调用分离上下文 方法,或者如果它是使用 NoTrackingMergeOption。

不变
对象自加载后未被修改 上下文或自上次以来 SaveChanges 方法是 调用。

修改
对象已更改,但 SaveChanges 方法未更改 被调用了。

我无法将 EntityObject 的 EntityState 属性显式设置为 Modified。它是只读的。

强类型 MVC 控制器与 EntityObjects 是不可能的吗?

【问题讨论】:

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


【解决方案1】:

您需要从您的 ObjectContext 中获取 ObjectStateManager。使用 ObjectStateManager,您可以显式设置对象的状态,而无需调用数据库:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(Guid id, SomeType Model)
{
    db.AttachTo(Model.GetType().Name, Model);

    ObjectStateManager stateMgr = db.ObjectStateManager;
    ObjectStateEntry stateEntry = stateMgr.GetObjectStateEntry(model);
    stateEntry.SetModified(); // Make sure the entity is marked as modified
    //db.ApplyPropertyChanges(Model.EntityKey.EntitySetName, Model);

    db.SaveChanges();
    return RedirectToAction("Index");
}

ObjectStateEntry 还允许您通过 SetModifiedProperty 应用更细粒度的状态更改数据。如果您调用 SetModified,EF 会将整个实体视为已修改,并将每个属性持久保存到数据存储中。使用 SetModifiedProperty,EF 可以优化查询并且只涉及实际更改的属性。使用 SetModifiedProperty 显然更复杂,因为您通常需要知道每个属性的原始值。

我希望这会有所帮助。 ObjectStateManager 是 EF 工具箱中一个强大的小工具,可以帮助改善 EF v1.0 原本病态的性能和效率。

【讨论】:

  • SetModifiedProperty 按预期工作。但是,SetModified 似乎并未将整个实体视为已修改。它不是“将所有属性持久化到数据存储”,而是不持久化。
  • 这有点奇怪......可能还有其他事情需要做......但这听起来像是某个地方的错误。
  • 关于 ObjectContext 的好答案和新天地,非常感谢您提供的知识。我最近遇到了一个类似的问题,我通过将 OC 临时变形为 DbContext 解决了这个问题:stackoverflow.com/questions/33714849/…
【解决方案2】:

我发现上述方法似乎都不适合我,但 MSDN 指南示例确实如此,您可以从上下文中获取原始项目,然后附加更新后的项目。

第二个例子:

http://msdn.microsoft.com/en-us/library/bb896248.aspx#Mtps_DropDownFilterText

private static void ApplyItemUpdates(SalesOrderDetail updatedItem){
// Define an ObjectStateEntry and EntityKey for the current object.
EntityKey key;
object originalItem;

using (AdventureWorksEntities advWorksContext =
    new AdventureWorksEntities())
{
    try
    {
        // Create the detached object's entity key.
        key = advWorksContext.CreateEntityKey("SalesOrderDetail", updatedItem);

        // Get the original item based on the entity key from the context
        // or from the database.
        if (advWorksContext.TryGetObjectByKey(key, out originalItem))
        {
            // Call the ApplyPropertyChanges method to apply changes
            // from the updated item to the original version.
            advWorksContext.ApplyPropertyChanges(
                key.EntitySetName, updatedItem);
        }

        advWorksContext.SaveChanges();
    }
    catch (InvalidOperationException ex)
    {
        Console.WriteLine(ex.ToString());
    }
}

}

【讨论】:

    【解决方案3】:

    这行得通:

    //
    // POST: /SomeType/Edit/5
    
    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Edit(Guid id, SomeType Model)
    {
        Model.EntityKey = (from SomeType s in db.SomeType
                           where s.Id == id
                           select s).FirstOrDefault().EntityKey;
        db.ApplyPropertyChanges(Model.EntityKey.EntitySetName, Model);
        db.SaveChanges();
        return RedirectToAction("Index");
    }
    

    但是有没有不查询数据库的方法呢?

    【讨论】:

      【解决方案4】:

      如果添加一行会发生什么:

      [AcceptVerbs(HttpVerbs.Post)]
      public ActionResult Edit(Guid id, SomeType Model)
      {
          db.AttachTo(Model.GetType().Name, Model);
          Model.SomeProperty = Model.SomeProperty; // This looks hacky... =(
          db.ApplyPropertyChanges(Model.EntityKey.EntitySetName, Model);
          db.SaveChanges();
          return RedirectToAction("Index");
      }
      

      状态会改变吗?

      【讨论】:

      • 我尝试了 Model.Id = Model.Id 但这导致了异常,因为该特定字段受实体框架保护。我没有尝试其他任何方法。
      【解决方案5】:

      我有这个工作,但我无法得到的是 SalesOrderDetail 的父实体 我该怎么办?

      SalesOrderDetail.SalesOrderHead 为空,实体引用也为空。 我的编辑例程只能访问 SalesOrderDetail 的 id。

      谢谢 斯里

      【讨论】:

      • 尝试“”链接开始一个新问题。您的问题会得到更多关注。
      猜你喜欢
      • 1970-01-01
      • 2011-08-31
      • 1970-01-01
      • 2011-12-06
      • 1970-01-01
      • 1970-01-01
      • 2011-07-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多