Je ne peux pas comprendre comment utiliser TryUpdateModel et enregistrer l'architecture MVC en même temps.
Si je ne me trompe pas, le travail avec les contextes de données doit être dans le modèle. Donc, un tel code
var db=new TestEverybody();//it is class, which was generated by EntityFramework
var currentTesting=db.Testing.(t => t.id == id).First();
doit être situé dans le modèle, pas dans le contrôleur, non?
Mais les exemples habituels d'utilisation de TryUpdateModel sont les suivants:
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");
}
De cette façon, ne casse-t-il pas l'architecture MVC? Nous travaillons avec une base de données dans le contrôleur, pas dans la classe spéciale Model.
Alors, quelle est la meilleure façon d'utiliser TryUpdateModel dans un vrai projet?
Depuis l'OP demandé, voici un exemple du modèle ViewModel, ou comme j'aime l'appeler - ASP.NET MVC fait correctement.
Alors pourquoi utiliser un modèle spécifique à la vue
Nous allons commencer avec une simple entité:
public class Product {
public int Id {get;set;}
public string Name {get;set;}
public string Description {get;set;}
public decimal Price {get;set;}
}
Et disons que vous avez un formulaire simple où l'utilisateur peut seulement mettre à jour le Name
et Description
du produit. Mais vous utilisez (le très gourmand) TryUpdateModel.
J'utilise donc un certain nombre d'outils (comme Fiddler) pour construire moi-même un POST et envoyer ce qui suit:
Nom = WhatverIWant & Description = UnluckyFool & Price = 0
Eh bien, le classeur de modèle ASP.NET MVC va inspecter la collection de formulaires en entrée, voir que ces propriétés existent sur votre entité et les lier automatiquement pour vous. Ainsi, lorsque vous appelez "TryUpdateModel" sur l'entité que vous venez de récupérer de votre base de données, toutes les propriétés correspondantes seront mises à jour (y compris le prix!). Il est temps pour une nouvelle option.
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;}
}
Cela ne contient que les propriétés dont nous avons besoin à notre avis. Notez que nous avons également ajouté des attributs de validation, des attributs d'affichage et des attributs spécifiques mvc.
En n'étant pas limité dans ce que nous avons dans notre modèle de vue, cela peut rendre vos vues beaucoup plus propres. Par exemple, nous pourrions afficher l'intégralité de notre formulaire d'édition en ayant les éléments suivants à notre avis:
@Html.EditorFor(model => model)
Mvc inspectera tous les attributs que nous avons ajoutés à notre modèle de vue et câblera automatiquement la validation, les étiquettes et les champs de saisie corrects (c'est-à-dire une zone de texte pour la description).
[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)
}
Il est assez évident d'après ce code ce qu'il fait. Nous n'avons aucun effet indésirable lorsque nous mettons à jour notre entité, car nous définissons explicitement des propriétés sur notre entité.
J'espère que cela explique suffisamment le modèle View-Model pour que vous souhaitiez l'utiliser.
Donc, ce code doit être situé dans le modèle, pas dans le contrôleur, n'est-ce pas?
Pas nécessairement. Personnellement, je préfère mettre le code d'accès aux données dans un référentiel. Utilisez ensuite l'injection de constructeur pour transmettre une implémentation de référentiel spécifique au contrôleur (par exemple, si j'utilisais EF, j'écrirais une implémentation de référentiel EF). Ainsi, le contrôleur ressemblera à ceci:
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");
}
}