Exemple réel de TryUpdateModel, ASP.NET MVC 3
Je ne comprends pas, comment utiliser TryUpdateModel et enregistrer l'architecture MVC en même temps.
Si Je ne me trompe pas, travailler avec datacontexts 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, n'est-ce pas?
Mais les exemples ussual 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");
}
Cette façon ne brise-t-elle pas l'architecture MVC? Nous travaillons avec la base de données dans le contrôleur, pas dans le modèle spécial classe.
Alors, quelle est la meilleure façon d'utiliser TryUpdateModel dans un projet réel?
2 réponses
Depuis que L'OP a 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
- Vous ne devez transmettre à votre vue que les informations dont elle a besoin.
- souvent, vous devrez ajouter des méta-données de vue supplémentaires (telles que des attributs de titre/description). Ceux-ci n'appartiennent pas à vos entités.
- L'utilisation de TryUpdateModel/UpdateModel est incorrecte. Ne pas utiliser (je vais vous expliquer pourquoi).
- C'est très rare que vos modèles de vue correspondent exactement à vos entités. Les gens finissent souvent par ajouter un cruft supplémentaire à leurs entités ou (pas beaucoup mieux) simplement en utilisant ViewBag plutôt que des propriétés de modèle de vue fortement typées.
- Si vous utilisez un ORM, vous pouvez rencontrer des problèmes avec des propriétés chargées paresseuses (N + 1). Vos vues ne devraient pas émettre de requêtes.
Nous allons commencer par une entité simple:
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 simple formulaire où l'utilisateur peut seulement mise à 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:
Name = WhatverIWant & Description=UnluckyFool & Price = 0
Eh bien le ASP.NET MVC model binder va inspecter la collection de formulaires d'Entrée, voir que ces propriétés existent sur votre entité et les lier automatiquement pour vous. Donc, lorsque vous appelez "TryUpdateModel" sur l'entité 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.
Voir Le Modèle Spécifique
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 ne se limitant pas à ce que nous avons dans notre modèle de vue, cela peut rendre vos points de vue beaucoup plus propres. Par exemple, nous pourrions rendre notre ensemble modifier le formulaire en ayant ce qui suit à 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).
Affichage du formulaire
[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 à partir de 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 le modèle View-Model suffit pour que vous souhaitiez l'utiliser.
, 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. Ensuite, utilisez l'injection du constructeur pour passer 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). Donc, 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");
}
}