views:

129

answers:

6

I've got some MVC code that serializes an EF 3.5 object into an anonymous type for return as a JSON result to an AJAX call on my page. The hurdle I have is that when I send the object back to the server via JSON, (and let the ModelBinder deserialize it for me into my EF type), I have to update it in my Entity Framework context manually. Or at least that's what I'm doing now. It has no EntityKey, so attaching it fails. I end up having to look up the old object and update it property by property. Any ideas around this? Is the solution to pass the EntityKey around with my object?

Here's what I have:

    public void Update(Album album)
    {
        using (var db = new BandSitesMasterEntities())
        {
            var albumToUpdate = db.Album.First(x => x.ID == album.ID);

            albumToUpdate.AlbumTitle = album.AlbumTitle;
            albumToUpdate.Description = album.Description;
            albumToUpdate.ReleaseYear = album.ReleaseYear;
            albumToUpdate.ImageURL = album.ImageURL;
            albumToUpdate.OtherURL = album.OtherURL;

            db.SaveChanges();
        }
    }

And here's what I'd like to do, or something similar:

    public void Update(Album album)
    {
        using (var db = new BandSitesMasterEntities())
        {
            db.Attach(album)
            db.SaveChanges();
        }
    }
A: 

There is no way around the entity key issue. You either have to add it to your anonymous type or I would recommend you port your code to using data services.

http://www.hanselman.com/blog/jQueryToShipWithASPNETMVCAndVisualStudio.aspx

which would allow you to do all of the db manipulation on the client side.

http://msdn.microsoft.com/en-us/data/bb931106.aspx

Nix
A: 

Did you try something like:

object original;
var key = contexte..CreateEntityKey("EntitySet", modified);
if(contexte.TryGetObjectByKey(key, out original))
{
    var originalEntity = (YourEntityType)original;
    // You have to mannualy set your entityKey
    originalEntity.YourEntityReference.EntityKey = new EntityKey("Entities.EntitySet", "Id", modified.YourEntity.Id);

    contexte.ApplyPropertyChanges("EntitySet", modified);
}
contexte.SaveChanges();

Assuming that your EntityReference are set by dropDown, you'll still have the Id

moi_meme
+1  A: 

or you could use AutoMapper to map those fields for you, so you'd just add one extra line to your example.

Robert Ivanc
2 lines actually - retrieve key and then map.
Robert Ivanc
A: 

Why not just use the UpdateModel or TryUpdateModel controller methods instead? It works really well with EF and you can even explicitly set the included property list.

The id parameter will auto-map via the MVC framework to the hidden field on your form specifying the id.

public void Update(int id, FormCollection collection)
{
    using (var db = new BandSitesMasterEntities())
    {
        var albumToUpdate = db.Album.First(x => x.ID == id);

        //use UpdateModel to update object, or even TryUpdateModel
        UpdateModel(albumToUpdate, new string[] { "AlbumTitle", "Description", "ReleaseYear", "ImageURL", "OtherURL" });

        db.SaveChanges();
    }
}
kayos
A: 

This became much easier for us in EF 4.0. This is what we did in EF 3.5:

public static void AttachAsModified(this ObjectContext objectContext, string setName, object entity,
                                    IEnumerable<String> modifiedFields)
{
    objectContext.AttachTo(setName, entity);
    ObjectStateEntry stateEntry = objectContext.ObjectStateManager.GetObjectStateEntry(entity);
    foreach (String field in modifiedFields)
    {
        stateEntry.SetModifiedProperty(field);
    }
}

And then:

using (var db = new BandSitesMasterEntities())
{
    db.AttachAsModified("Album", album, new string[] { "AlbumTitle", "Description", "ReleaseYear", "ImageURL", "OtherURL" })
    db.SaveChanges();
}

It becomes more complicated if you have foreign key constraints, but it looks like you don't.

StriplingWarrior
A: 

In your Album entity's partial class you may define a CopyFrom function and call it from your Update function

partial class Album
{
   public void CopyFrom(Album album)
   {
   //individual field copying here
   }
}


 public void Update(Album album) 
    { 
      ...
      albumToUpdate.CopyFrom(album);
      ...
    }
cellik