2

I posted this question, but there was a guffaw where I overwrote my actual question and just posted code and then it was voted to be closed. I figured the question was pretty much fubared and didn't get its fair shake, so I'm posting it again.

I'm using Entity Framework 4.1. I have a form that has a good number of fields on it. The table itself actually has more fields than what is on the form. I'm trying to find a way to update just the fields that have changed. I found an example of that here:

EntityFramework update partial model

I've revised that to the code below so that I don't have to specify 40+ fields manually. I'm hoping that there's a cleaner way to do this than what is below. Is there?

Warning the code below is a first draft and is rather crude. All suggestions are welcomed. Thanks!

    [HttpPost]
    public ActionResult Edit(Location location, FormCollection fields)
    {
        if (ModelState.IsValid)
        {
            //db is my context
            db.Locations.Attach(location);

            StringBuilder sb = new StringBuilder();

            //Get properties of Location object
            PropertyInfo[] pi = typeof(Location).GetProperties();

            //loop over keys of fields submitted by the post
            foreach (string submittedField in fields.Keys)
            {
                //If a property name on the Location object matches a field name
                //of one of the submitted properties then mark the property as 
                //modified
                if (pi.Any(prop => prop.Name.Equals(submittedField)) && 
                    !"ID".Equals(submittedField) )
                {
                    db.Entry(location).Property(submittedField).IsModified = true;
                    sb.AppendLine(submittedField + "Value: " + db.Entry(location).Property(submittedField).CurrentValue );
                }
            }

            LogUtil.WriteCondensed(sb.ToString());

            //Save changes to the database
            db.SaveChanges();
            return RedirectToAction("Index");
        }
        return View(location);
    }
Community
  • 1
  • 1
jason
  • 2,219
  • 5
  • 33
  • 66

1 Answers1

2

I wouldn't rely on what's passed to your Edit action to know what can be updated and what cannot for security reasons (remember that what's posted to the server can be changed by the client).

public class YourEntity
{
    public long ID { get; set; }

    // Updatable fields
    public string Field1 { get; set; }
    ....
}

In the view, use an hidden field for the ID of the object to update (razor syntax):

@model YourEntity
...
@Html.HiddenFor(model => model.ID)
...
@Html.EditorFor(model => model.Field1)

I would then:

  1. check the user has rights to update the entity
  2. retrieve the actual entity from the DB using its ID
  3. manually update property by property
  4. save to DB

Controller:

[HttpPost]
public ActionResult Edit(YourEntity model)
{
    try
    {
        yourServiceLayer.Update(User.Identity.Name, model);
    }
    catch (CustomSecurityException)
    {
        ...
    }
}

Service:

public class YourServiceLayer
{
    public YourEntity Update(string userName, YourEntity entity)
    {
        // Check user has rights to edit the entity (if necessary)
        if (this.CanUpdate(userName, entity.ID))
        {
            // Gets actual entity from DB
            var yourDbEntity = this.GetByID(entity.ID);

            // Updates each property manually
            yourDbEntity.Field1 = entity.Field1;
            ....

            // Saves to DB
            this.Save(yourDbEntity);
            return yourDbEntity;
        }
        else
        {
            // Security exception
            throw new CustomSecurityException(...);
        }   
    }

    public bool CanUpdate(string userName, long entityID)
    {
        // Insert logic here
        return ....;
    }

    ...
}

If you have 40+ fields, then yes it's boring to write, but at least you have full control on properties that can be updated and properties that cannot.

ken2k
  • 48,145
  • 10
  • 116
  • 176
  • 1
    I'm really not trying to come off as lazy, but if I added a custom Data Annotation to my view model to denote which fields should be saved during an edit, would that seem viable? I'd still have to use reflection over all the Location properties to get the annotation, though, wouldn't I? – jason Jan 03 '13 at 13:44