What is the best way to maintain an entity's original properties when they are not included in MVC binding from edit page?

谁说我不能喝 提交于 2019-12-23 02:52:10

问题


I have an ASP.NET MVC view for editing a model object. The edit page includes most of the properties of my object but not all of them -- specifically it does not include CreatedOn and CreatedBy fields since those are set upon creation (in my service layer) and shouldn't change in the future.

Unless I include these properties as hidden fields they will not be picked up during Binding and are unavailable when I save the modified object in my EF 4 DB Context. In actuality, upon save the original values would be overwritten by nulls (or some type-specific default).

I don't want to drop these in as hidden fields because it is a waste of bytes and I don't want those values exposed to potential manipulation.

Is there a "first class" way to handle this situation? Is it possible to specify a EF Model property is to be ignored unless explicitly set?


回答1:


Use either:

public bool SaveRecording(Recording recording)
{
    // Load only the DateTime property, not the full entity
    DateTime oldCreatedOn = db.Recordings
       .Where(r => r.Id == recording.Id)
       .Select(r => r.CreatedOn)
       .SingleOrDefault();

    recording.CreatedOn = oldCreatedOn;

    db.Entry(recording).State = EntityState.Modified;
    db.SaveChanges();

    return true;
}

(Edit: The query only loads the CreatedOn column from the database and is therefore cheaper and faster than loading the full entity. Because you only need the CreatedOn property using Find would be unnecessary overhead: You load all properties but need only one of them. In addition loading the full entity with Find and then detach it afterwards could be shortcut by using AsNoTracking: db.Recordings.AsNoTracking().SingleOrDefault(r => r.Id == recording.Id); This loads the entity without attaching it, so you don't need to detach the entity. Using AsNoTracking makes loading the entity faster as well.)

Edit 2

If you want to load more than one property from the database you can project into an anonymous type:

public bool SaveRecording(Recording recording)
{
    // Load only the needed properties, not the full entity
    var originalData = db.Recordings
       .Where(r => r.Id == recording.Id)
       .Select(r => new
       {
           CreatedOn = r.CreatedOn,
           CreatedBy = r.CreatedBy
           // perhaps more fields...
       })
       .SingleOrDefault();

    recording.CreatedOn = originalData.CreatedOn;
    recording.CreatedBy = originalData.CreatedBy;
    // perhaps more...

    db.Entry(recording).State = EntityState.Modified;
    db.SaveChanges();

    return true;
}

(End of Edit 2)

Or:

public bool SaveRecording(Recording recording)
{
    Recording oldVersion = db.Recordings.Find(recording.Id);

    recording.CreatedOn = oldVersion.CreatedOn;

    // flag only properties as modified which did really change
    db.Entry(oldVersion).CurrentValues.SetValues(recording);

    db.SaveChanges();

    return true;
}

(Edit: Using CurrentValues.SetValues flags only properties as Modified which indeed have been changed compared to the original state in the database. When you call SaveChanges EF will sent only the properties marked as modified in an UPDATE statement to the database. Whereas setting the state in Modified flags all properties as modified, no matter if they really changed or not. The UPDATE statement will be more expensive because it contains an update for all columns.)




回答2:


If you don't want to send that data down to the client, I don't see any other option but to load up the original from the db in your service layer when you save and merge those original property values back in to the updated object. There's no way for EF to know that you didn't set those values to null on purpose and don't actually want to save them that way.




回答3:


You could implement your own model binder that ignores the properties you don't want to pass around. Start here - http://lostechies.com/jimmybogard/2009/03/18/a-better-model-binder/




回答4:


I think when you going to update use getById to get all the entity and then set your relevant properties and then you can update. It will be easy if you are using some kind of mapper (Automapper) to map your properties from view model to loaded entity from DB.




回答5:


If you want to avoid making an additional (unnecessary) call to your database before every update, you can either use self-tracking entities or set StoreGeneratedPattern="Identity" for those fields in your entity model. And yes, Identity is misleading, but that sounds like the setting you'd want:

Identity A value is generated on insert and remains unchanged on update.

http://msdn.microsoft.com/en-us/library/system.data.metadata.edm.storegeneratedpattern.aspx



来源:https://stackoverflow.com/questions/8145635/what-is-the-best-way-to-maintain-an-entitys-original-properties-when-they-are-n

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!