2013-05-22 25 views
6

mam mniej lub bardziej standardowe patrząc model:Wykrywanie zmiany stanu własności modelu, kontroler, przy użyciu Entity Framework

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

    public DateTime StartDate { get; set; } 
    public int Duration { get; set; } 
} 

Jeśli użytkownik modyfikuje StartDate lub projekt Duration muszę wywołać funkcję aktualizacji symulacja. Aby to osiągnąć, chciałbym wykryć zmianę stanu pól StartDate i Duration w kontrolerze.

Coś takiego:

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

Oto przykład tego, co metoda kontroler będzie wyglądać następująco:

[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); 
} 

Każdy pomysł, w jaki sposób można to osiągnąć?

Odpowiedz

7

Uważam, że można porównać edytowany obiekt z oryginałem odczytanym z bazy danych.

Coś jak:

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); 
} 
+1

Próbowałem tego.Pojawia się następujący błąd: 'Obiekt z tym samym kluczem już istnieje w ObjectStateManager. ObjectStateManager nie może śledzić wielu obiektów za pomocą tego samego klucza. Opis: Wystąpił nieobsługiwany wyjątek podczas wykonywania bieżącego żądania WWW. Sprawdź ślad stosu, aby uzyskać więcej informacji o błędzie i skąd pochodzi w kodzie. Szczegóły wyjątku: System.InvalidOperationException: Obiekt o tym samym kluczu już istnieje w ObjectStateManager. ObjectStateManager nie może śledzić wielu obiektów z tym samym kluczem. " – Chopo87

+0

Z lub bez" db.Entry (oryginał) .State = EntityState.Modified; '? –

+0

Dobra rada, pozwól mi spróbować, że – Chopo87

2

Jeśli chcesz zrobić to bez sprawdzania swojej warstwy perswistycznej, domyślam się, że stare wartości należy dodać jako pola w twoim modelu, a następnie zachować je na stronie, ponieważ ukryte pola to najprostszy sposób na rozwiązanie tego problemu.

Więc dodać CurrentStartDate i CurrentDuration w modelu:

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; } 
} 

a następnie dodać ukrytych pól ze starymi wartościami w widoku:

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

To daje coś porównać wybrane wartości w działaniu kontrolera.

+1

Właściwie wolałbym wykonać wszystkie kontrole w kontrolerze, jeśli to możliwe, zachowuje kod czystszy. Czy mógłbyś rozwinąć metodę "sprawdzania swojej warstwy trwałości", która brzmi jak to, co próbuję osiągnąć. – Chopo87

+1

Następnie należy pobrać bieżący projekt z bazy danych i sprawdzić stare wartości i porównać z wartościami, które otrzymujesz od klienta. – KMan

+1

Próbowałem już: Otrzymuję następujący wyjątek 'Obiekt z tym samym kluczem już istnieje w ObjectStateManager. ObjectStateManager nie może śledzić wielu obiektów tym samym kluczem. " – Chopo87

6

Można go rozwiązać poprzez przeprowadzenie stare wartości poprzez ViewBag.

w akcji:

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

Dodaj ukryte elementy do widzenia

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

Dodaj te parametry do metody post i sprawdzić je na przemian

[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); 
} 
+0

Preferuję to rozwiązanie, ponieważ nie wiąże się z dodatkowym obiegiem do bazy danych –

0

Używaj .AsNoTracking() .FirstOrDefault w celu pobrania oryginalnego obiektu do porównania:

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); 
} 
Powiązane problemy