Detecting model state changes in the controller using Entity Framework

I have a more or less standard looking model:

public class Project { public int ID { get; set; } //... some more properties public DateTime StartDate { get; set; } public int Duration { get; set; } } 

If the user modifies StartDate or project Duration , I need to call a function to update the simulation. To do this, I would like to detect a change in the state of the StartDate and Duration fields in the controller.

Something like that:

 if(project.StartDate.stateChange() || project.Duration.stateChange()) 

Here is an example of what the controller method looks like:

 [HttpPost] public ActionResult Edit(Project project) { if (ModelState.IsValid) { if(project.StartDate.stateChange() || project.Duration.stateChange()) doSomething(); db.Entry(project).State = EntityState.Modified; db.SaveChanges(); return RedirectToAction("Index"); } return View(project); } 

Any idea how I can achieve this?

+6
source share
4 answers

I believe that you can compare the edited object with the original one read from the database.

Sort of:

 public ActionResult Edit(Project project) { if (ModelState.IsValid) { var original = db.Find(project.ID); bool changed = original.StartDate != project.StartDate || original.Duration != project.Duration; if (changed) { original.StartDate = project.StartDate; original.Duration = project.Duration; doSomething(); db.Entry(original).State = EntityState.Modified; //not sure if this is necessary as it should be tracked by EF (because it is read from the database) db.SaveChanges(); } } return View(project); } 
+7
source

You can solve this by transferring old values โ€‹โ€‹through the ViewBag.

In action:

 public ActionResult Edit(int? id) { //...Your Code ViewBag.OrigStartDate = project.StartDate; ViewBag.OrigDuration = project.Duration; return View(project); } 

Add hidden items to view

 ... @Html.Hidden("OrigStartDate", (DateTime)ViewBag.OrigStartDate) @Html.Hidden("OrigDuration", (int)ViewBag.OrigDuration) ... 

Add these parameters to the post method and check for changes.

 [HttpPost] public ActionResult Edit(DateTime OrigStartDate, int OrigDuration) { if (ModelState.IsValid) { if (OrigStartDate != project.StartDate || OrigDuration != project.Duration) doSomething(); db.Entry(project).State = EntityState.Modified; db.SaveChanges(); return RedirectToAction("Index"); } ViewBag.FileTypeId = new SelectList(db.FileTypes, "Id", "TypeName", dbinfo.FileTypeId); return View(project); } 
+6
source

If you want to do this without asking for your level of stability, I think adding the old values โ€‹โ€‹as fields in your model and then storing them on the page, as hidden fields is the easiest way to solve this problem.

Add CurrentStartDate and CurrentDuration to your model:

 public class Project { public int ID { get; set; } //... some more properties public DateTime StartDate { get; set; } public int Duration { get; set; } public DateTime CurrentStartDate { get; set; } public int CurrentDuration { get; set; } } 

and then add hidden fields with old values โ€‹โ€‹in your view:

 @Html.HiddenFor(model => model.CurrentStartDate ) @Html.HiddenFor(model => model.CurrentDuration ) 

This will give you the opportunity to compare the selected values โ€‹โ€‹with the action of your controller.

+2
source

Use .AsNoTracking (). FirstOrDefault to retrieve the source object for comparison:

 public ActionResult Edit(Project project) { if (ModelState.IsValid) { Project original = db.AsNoTracking().FirstOrDefault( p => p.ID == project.ID); if (original.StartDate != project.StartDate || original.Duration != project.Duration) doSomething(); db.Entry(project).State = EntityState.Modified; db.SaveChanges(); } return View(project); } 
0
source

Source: https://habr.com/ru/post/945559/


All Articles