Strongly-Typed ASP.NET MVC with Entity Framework

This code fails to actually save any changes:

//
// 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 creates the object Model as a Department type EntityObject with an EntityState value of Detached.

After using the AttachTo method, its EntityState becomes Unchanged.

MSDN on Attaching Objects (Entity Framework)

Objects are attached to the object
context in an Unchanged state.

Because of its Unchanged state, the method ApplyPropertyChanges does nothing.

I want it to instead have state Modified.

MSDN on EntityState Enumeration

Detached
The object exists but it is not being tracked by Object
Services. An entity is in this state
immediately after it has been created
and before it is added to the object
context. An entity is also in this
state after it has been removed from
the context by calling the Detach
method or if it is loaded using a
NoTrackingMergeOption.

Unchanged
The object has not been modified since it was loaded into
the context or since the last time
that the SaveChanges method was
called.

Modified
The object is changed but the SaveChanges method has not
been called.

I cannot explicitly set an EntityObject’s EntityState property to Modified. It is read only.

Is it just impossible to have strongly-typed MVC controllers with EntityObjects?

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

You need to get the ObjectStateManager from your ObjectContext. With the ObjectStateManager, you can explicitly set the state for your object without needing to make a call to the database:

[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");
}

The ObjectStateEntry also allows you to apply finer-grained state change data via the SetModifiedProperty. If you call SetModified, EF will treat the entire entity as modified, and persist every property to the data store. With SetModifiedProperty, EF can optimize the queries and only involve the properties that have actually changed. Using SetModifiedProperty is obviously more complex, as you usually need to know the original value of each property.

I hope this helps. ObjectStateManager is a powerful little tool in the EF toolbox, and can help improve EF v1.0’s otherwise morbid performance and efficiency.

Method 2

I found none of the above seemed to work for me, but the MSDN guide example did which is where you get the original item from the context, and then attach the updated item.

Second example:

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

}

Method 3

This works:

//
// 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");
}

But is there a way without querying the database?

Method 4

What happens if you add one line:

[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");
}

Does the state change?

Method 5

I have this working, but what iam not able to get at is the parent entity of SalesOrderDetail
How can i get at it?

SalesOrderDetail.SalesOrderHead is null and also entityreference is null.
My edit routine has access to the id of SalesOrderDetail only.

Thanks
Sri


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x