0

Say I have a bunch of boolean properties on my entity class public bool isActive etc. Values which will be manipulated by setting check boxes in a web application. I will ONLY be posting back the one changed name/value pair and the primary key at a time, say { isActive : true , NewsPageID: 34 } and the default model binder will create a NewsPage object with only those two properties set. Now if I run the below code it will not only update the values for the properties that have been set on the NewsPage object created by the model binder but of course also attempt to null all the other non set values for the existent entity object because they are not set on NewsPage object created by the model binder.

Is it possible to somehow tell entity framework not to look at the properties that are set to null and attempt to persist those changes back to the retrieved entity object and hence database ? Perhaps there's some code I can write that will only utilize the non-null values and their property names on the NewsPage object created by model binder and only attempt to update those particular properties ?

    [HttpPost]
    public PartialViewResult SaveNews(NewsPage Np)
    {
        Np.ModifyDate = DateTime.Now;
        _db.NewsPages.Attach(Np);
        _db.ObjectStateManager.ChangeObjectState(Np, System.Data.EntityState.Modified);
        _db.SaveChanges();
        _db.Dispose();


        return PartialView("MonthNewsData");
    }

I can of course do something like below, but I have a feeling it's not the optimal solution. Especially considering that I have like 6 boolean properties that I need to set.

[HttpPost]
public PartialViewResult SaveNews(int NewsPageID, bool isActive, bool isOnFrontPage)
{
        if (isActive != null)   { //Get entity and update this property }
        if (isOnFontPage != null) { //Get entity and update this property }
}
LaserBeak
  • 3,257
  • 10
  • 43
  • 73
  • Would be probably easier to pass the unchanged props to the model binder, or alternatively write a custom one and get the full object there. – veblock Jul 06 '12 at 03:49

3 Answers3

1

API is not strongly typed but you can do it as follows. DbContext API has better support for this.

[HttpPost]
public PartialViewResult SaveNews(NewsPage Np)
{
    Np.ModifyDate = DateTime.Now;
    _db.NewsPages.Attach(Np);
    var entry = _db.ObjectStateManager.GetObjectStateEntry(Np);

    var cv = entry.CurrentValues;

    if (isActive)
    {
        cv.SetBoolean(cv.GetOrdinal("isActive"), true);
    }

    _db.SaveChanges();
    _db.Dispose();

    return PartialView("MonthNewsData");
}
Eranga
  • 32,181
  • 5
  • 97
  • 96
0

You can go for two options

  1. Register a custom model binder for that action. In the custom model binder you have to get the complete object from the database and only update the POSTed properties.

  2. Use a view model. Instead of directly having the NewsPage model as the action parameter. You can create a custom view model that wraps the necessary properties. Inside the action you have to make a call to db to get the complete NewsPage instance and update only the corresponding properties from the view model.

VJAI
  • 32,167
  • 23
  • 102
  • 164
  • The model binder solution sounds feasible, considering it will only match the set and only posted name/value pair against the model, which can be the complete object from the db in my case. The ViewModel approach though does not really present any advantages to dealing with the NewsPage object. Sure I can have a separate property for name, value and pageid but this can just as well be pulled from NewsPage object. – LaserBeak Jul 06 '12 at 04:39
0

Somewhat ugly, but did the trick in my case without having to create and register custom model binder or using multiple if statements.

    [HttpPost]
    public void SaveNews(string propname, bool propvalue, int PageID)
    {
        var prop = typeof(NewsPage).GetProperties().FirstOrDefault(x => x.Name.ToLower() == propname.ToLower());
        var Np = _db.NewsPages.FirstOrDefault(x => x.PageID == PageID);
        prop.SetValue(Np, propvalue, null);

         Np.ModifyDate = DateTime.Now;
        _db.SaveChanges();
        _db.Dispose();

    }
LaserBeak
  • 3,257
  • 10
  • 43
  • 73