views:

339

answers:

2

My form includes a subset of Client entity properties and I also include a hidden field that holds an ID of the client. The client entity itself is provided via the GET Edit action.

Now I want to do entity update but so far I've only been trying without first loading the entity from the DB. Because the client object that comes in POST Edit has everything it needs. I want to update just those properties on the entity in datastore.

I've ported my app from 3.5 to 4.0 RC1 and my code looks like this now:

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Edit(Client client)
    {
        try
        {
            using (DocInvoiceEntities edmx = new DocInvoiceEntities())
            {
                if (string.IsNullOrEmpty(client.client_firstname))
                    ViewData.ModelState.AddModelError("client_firstname", "Firstname!");

                if (string.IsNullOrEmpty(client.client_lastname))
                    ViewData.ModelState.AddModelError("client_lastname", "Lastname!");

                // postcode
                client.PostCode = (from p in edmx.PostCodes where p.postcode.Equals(client.PostCode.postcode) select p).First();

                // check for errors
                if (!ViewData.ModelState.IsValid)
                    throw new InvalidOperationException();

                // save changes to datastore
                edmx.Clients.Attach(edmx.Clients.Single(c => c.client_id == client.client_id));
                edmx.Clients.ApplyCurrentValues(client);
                edmx.SaveChanges();

            }
            return RedirectToAction("Create", "Invoice");
        }
        catch
        {
            return View();
        }

ApplyCurrentValues() call throws this exception: "The existing object in the ObjectContext is in the Added state. Changes can only be applied when the existing object is in an unchanged or modified state."

A: 

I'm not aware of a nice way to do this. It seems like it should be a case of attaching the edited object and saving changes, but the framework doesn't work that way.

In short the SaveChanges magic only works on entity objects that were created from the context you are working with. Entity objects created by the controller don't qualify.

Try something like this (MVC 2 and EF 4)

[HttpPost]
public ActionResult Edit(Client clientToEdit)
{
    db.Client.Attach(db.Client.Single(c => c.ID == clientToEdit.ID));
    db.Client.ApplyCurrentValues(clientToEdit);
    db.SaveChanges();
}

It does require a query in order to update, but I haven't come across a robust way around it. d

Cephas
I had to upgrade to 4.0 from 3.5 to make this available but I have it now, however at ApplyCurrentValues there is an exception:"The existing object in the ObjectContext is in the Added state. Changes can only be applied when the existing object is in an unchanged or modified state."
mare
Looks like your Client.PostCode is a relationship not a scalar property.Changing a relationship puts the object into the 'Added' state.If you call ApplyCurrentValues to update the scalar properties, then change the PostCode it might work.
Cephas
+1  A: 

If your sending over your EntityKey Ids from your and simply want to save your posted values then all you need is:

edmx.Clients.Attach(client);
edmx.SaveChanges();
jfar
Thanks that worked but why did Cephas recommended ApplyCurrentValues()?
mare
idk, but thats why I voted him down
jfar