I cannot come up with a solution to a problem that's best described verbally and with a little code. I am using VS 2013, MVC 5, and EF6 code-first; I am also using the MvcControllerWithContext scaffold, which generates a controller and views that support CRUD operations.
Simply, I have a simple model that contains a CreatedDate value:
public class WarrantyModel
{
[Key]
public int Id { get; set; }
public string Description { get; set; }
DateTime CreatedDate { get; set; }
DateTime LastModifiedDate { get; set; }
}
The included MVC scaffold uses the same model for its index, create, delete, details, and edit views. I want the CreatedDate in the 'create' view; I do not want it in the 'edit' view because I do not want its value to change when the edit view is posted back to the server and I don't want anyone to be able to tamper with the value during a form-post.
Ideally, I don't want the CreatedDate to ever get to the Edit view. I have found a few attributes I can place on the model's CreatedDate property (for example, [ScaffoldColumn(false)]) that prevent it from appearing on the Edit view, but then I'm getting binding errors on postback because the CreatedDate ends up with a value of 1/1/0001 12:00:00 AM. That's because the Edit view is not passing a value back to the controller for the CreatedDate field.
I don't want to implement a solution that requires any SQL Server changes, such as adding a trigger on the table that holds the CreatedDate value. If I wanted to do a quick-fix, I would store the CreatedDate (server-side, of course) before the Edit view is presented and then restore the CreatedDate on postback--that would let me change the 1/1/0001 date to the CreatedDate EF6 pulled from the database before rendering the view. That way, I could send CreatedDate as a hidden form field and then overwrite its value in the controller after postback, but I don't have a good strategy for storing server-side values (I don't want to use Session variable or the ViewBag).
I looked at using [Bind(Exclude="CreatedDate")], but that doesn't help.
The code in my controller's Edit post-back function looks like this:
public ActionResult Edit([Bind(Include="Id,Description,CreatedDate,LastModifiedDate")] WarrantyModel warrantymodel)
{
if (ModelState.IsValid)
{
db.Entry(warrantymodel).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(warrantymodel);
}
I thought I might be able to examine the db.Entry(warrantymodel) object within the if
block above and examine at the OriginalValue for CreatedDate, but when I try to access that value (as shown next), I get an exception of type 'System.InvalidOperationException':
var originalCreatedDate = db.Entry(warrantymodel).Property("CreatedDate").OriginalValue;
If I could successfully examine the original CreatedDate value (i.e., the one that is already in the database) I could just overwrite whatever the CurrentValue is. But since the above line of code generates an exception, I don't know what else to do. (I thought about querying the database for the value but that's just silly since the database was already queried for the value before the Edit view was rendered).
Another idea I had was to change the IsModified value to false for the CreatedDate value but when I debug then I discover that it is already is set to false in my 'if' block shown earlier:
bool createdDateIsModified = db.Entry(warrantymodel).Property("CreatedDate").IsModified;
I am out of ideas on how to handle this seemingly simple problem. In summary, I do not want to pass a model field to an Edit view and I want that field (CreatedDate, in this example) to maintain its original value when the other Edit fields from the view are posted back and persisted to the database using db.SaveChanges().
Any help/thoughts would be most appreciated.
Thank you.