Prawdziwy przykład TryUpdateModel, ASP.NET MVC 3

Nie mogę zrozumieć, jak używać TryUpdateModel i zapisać architekturę MVC w tym samym czasie.

Jeśli się nie mylę, praca z DataContext musi być w modelu. Więc taki kod

var db=new TestEverybody();//it is class, which was generated by EntityFramework 
var currentTesting=db.Testing.(t => t.id == id).First();

Musi znajdować się w modelu, a nie w kontrolerze, czyż nie?

Ale przykłady użycia TryUpdateModel są następujące:

    public ActionResult Edit(Testing obj)//Testing collection
    {
        var db = new TestEverybody();
        var currentTesting=db.Testing.(t => t.id == obj.id).First();
        TryUpdateModel(currentTesting);
        db.SaveChanges();            
        return RedirectToAction("Index");
    }

Czy ten sposób nie łamie architektury MVC? Pracujemy z bazą danych w kontrolerze, a nie w specjalnym modelu klasy.

Więc, jaki jest najlepszy sposób, aby użyć TryUpdateModel w prawdziwym projekcie?

Author: Sir Hally, 2011-10-12

2 answers

Ponieważ OP zapytał, oto przykład wzorca ViewModel, lub jak to lubię nazywać - ASP.NET MVC zrobione poprawnie.

Więc po co używać modelu specyficznego dla widoku

  1. powinieneś przekazać tylko te informacje, które są ci potrzebne.
  2. często musisz dodać dodatkowe metadane widoku (takie jak atrybuty tytułu/opisu). Te nie należą do Waszych Bytów.
  3. używanie TryUpdateModel / UpdateModel jest złe. Nie używaj (wyjaśnię dlaczego).
  4. to bardzo rzadko, że twoje modele widoku będą dokładnie pasowały do twoich jednostek. Ludzie często kończą na dodaniu dodatkowego cruft do swoich jednostek lub (niewiele lepiej) po prostu używając ViewBag, a nie mocno wpisanych właściwości modelu widoku.
  5. Jeśli używasz ORM, możesz napotkać problemy z właściwościami Lazy loaded (N+1). Twoje widoki nie powinny wysyłać zapytań.

Zaczniemy od prostej istoty:

public class Product {
    public int Id {get;set;}
    public string Name {get;set;}
    public string Description {get;set;}
    public decimal Price {get;set;}
}

I powiedzmy, że masz prosty formularz, w którym użytkownik może tylko zaktualizować Name i Description produktu. Ale używasz (bardzo chciwy) TryUpdateModel.

Więc używam dowolnej liczby narzędzi (takich jak Fiddler) do samodzielnego konstruowania posta i wysyłania:

Name=WhatverIWant&Description = UnluckyFool&Price = 0

Cóż ASP.NET MVC model binder zamierza sprawdzić kolekcję formularzy wejściowych, sprawdzić, czy te właściwości istnieją na Twoim obiekcie i automatycznie powiązać je za Ciebie. Więc kiedy wywołujesz "TryUpdateModel" na jednostce właśnie pobrałeś ze swojej bazy danych, wszystkie pasujące właściwości zostaną zaktualizowane (w tym Cena!). Czas na nową opcję.

Zobacz Szczegółowy Model

public class EditProductViewModel {
    [HiddenInput]
    public Guid Id {get;set;}

    [Required]
    [DisplayName("Product Name")]
    public string Name {get;set;}

    [AllowHtml]
    [DataType(DataType.MultilineText)]
    public string Description {get;set;}
}

Zawiera tylko te właściwości, których potrzebujemy w naszym przekonaniu. Zauważ, że dodaliśmy również atrybuty walidacji, atrybuty wyświetlania i niektóre atrybuty specyficzne dla mvc.

Nie ograniczając się do tego, co mamy w naszym modelu widzenia, może sprawić, że Twoje poglądy będą dużo czystsze. Na przykład, możemy renderować całą naszą edytuj formularz, mając w naszym przekonaniu:

@Html.EditorFor(model => model)

Mvc sprawdzi wszystkie atrybuty, które dodaliśmy do naszego modelu widoku i automatycznie połączy walidację, etykiety i prawidłowe pola wejściowe (tj. pole tekstowe do opisu).

Zamieszczanie formularza

[HttpPost]
public ActionResult EditProduct(EditProductViewModel model) {

    var product = repository.GetById(model.Id);

    if (product == null) {
        return HttpNotFound();
    }

    // input validation
    if (ModelState.IsValid) {

        // map the properties we **actually** want to update
        product.Name = model.Name;
        product.Description = model.Description;

        repository.Save(product);

        return RedirectToAction("index");
    }

    return View(model)
}

To dość oczywiste z tego kodu, co robi. Nie mamy żadnych niepożądanych efektów, gdy aktualizujemy naszą jednostkę, ponieważ wyraźnie ustawiamy właściwości na naszej jednostce.

Mam nadzieję, że to wyjaśnia wzorzec View-Model wystarczy, abyś chciał go użyć.

 109
Author: Ben Foster,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-10-15 09:45:34

Więc taki kod musi być umieszczony w modelu, a nie w kontrolerze, czyż nie?

Niekoniecznie. Osobiście wolę umieścić kod dostępu do danych w repozytorium. Następnie użyj constructor injection, aby przekazać jakąś konkretną implementację repozytorium do kontrolera (na przykład gdybym używał EF, napisałbym implementację repozytorium EF). Więc kontroler będzie wyglądał tak:
public class HomeController: Controller
{
    private readonly IMyRepository _repository;
    public HomeController(IMyRepository repository)
    {
        _repository = repository;
    }

    public ActionResult Edit(int id)
    {
        var currentTesting = _repository.GetTesting(id);
        TryUpdateModel(currentTesting);
        _repository.SaveChanges();            
        return RedirectToAction("Index");
    }
}
 18
Author: Darin Dimitrov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-10-12 06:16:30