Entity-Framework to Update Exception?

.net-4.0 asp.net-mvc c# entity-framework

Question

Hi,

I have some issues with the upgrade for my ASP.NET MVC website, which uses EntityFramework.

My update code looks like this:

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;

I get the following error while running context.Refresh:

Either this ObjectStateManager is not associated to the element at index 0 in the collection of objects to refresh, or it has a null EntityKey property value.

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 

This issue has occurred to me before. At first, I speculated that it may be related to the database relations, however once they were eliminated from the affected table, the same problem persisted.

What is the origin of the adCategoryFilter?

Data from the ViewObject is first loaded into the newly created adCategoryFilter (from the website). The needed information, such as the filter ID, is present (to map the filter to correct row in db).

Please elaborate on the cause of my issue and provide a solution.

BestRegards

1
3
12/13/2010 3:18:45 PM

Accepted Answer

As a result of utilizing ASP.NET MVC, your working environment is stateless. This indicates that when a request has been processed, "Entity Framework Memory" or "The Graph" are gone.

As a result, you must explicitly inform EF that you intend to add or update.

How to accomplish it is as follows:

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

This is known as the stub approach.

Simply said, to update an entity, you must first create a new entity with the same entity key (in your case, the entity key is "Id").

Then you "connect" this stub (make it visible to the EF internal graph), update the data on the stub using your entity, and save the changes.

I have a multi-layered architecture and employ POCOs, custom viewmodels, etc., so I can't use UpdateModel. As a result, I wrote a custom "UpdateModel" method on my service/repository that does a (more involved) version of the aforementioned.

Avoid using the statement "if Id 1, it's an add" with ASP.NET MVC since it will attempt to do a add even though you may be performing a update if you fail to bind the ID on the view.

Make your intentions clearer by having distinct action methods for Add and Update.

HTH.

5
12/13/2010 11:32:04 PM

Popular Answer

Try getting the object and modifying its attributes instead of refreshing using a tool like an auto-mapper (or UpdateModel in MVC controller)

The EntityKey is something distinct from the id property with additional functionality. The issue arises because your freshly generated object is lacking this information.

The pattern is roughly as follows (I'm not a C# person, so pardon the syntax):

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

The key distinction is that the EntityKey on the newly retrieved object has been appropriately configured. Although the id property may be used to detect a new or existing object, the EntityKey is more than just that one field.



Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow