85 votes

Comment la carte Afficher le Modèle vers Modèle de Domaine dans un POST de l'action?

Chaque article trouvé dans l'Internet à l'aide de Viewmodel et en utilisant Automapper donne les lignes directrices de la "Contrôleur -> Affichage", en direction de la cartographie. Vous prenez un modèle de domaine avec toutes les Listes de sélection dans l'un spécialisé ViewModel et passer à la vue. C'est clair et fin.
Le point de vue a une forme, et, finalement, nous sommes dans le POST de l'action. Ici, tous les Classeurs de Modèle venu de la scène avec [évidemment] un autre Modèle de Vue qui est [évidemment] liées à l'origine ViewModel au moins dans le cadre de conventions de nommage pour l'amour de liaison et de validation.

Comment voulez-vous correspondre à votre Modèle de Domaine?

Que ce soit une action d'insertion, on pourrait utiliser la même Automapper. Mais si c'était une action de mise à jour? Nous devons récupérer notre Entité de Domaine à partir du Référentiel, mise à jour de ses propriétés en fonction des valeurs dans le ViewModel et les enregistrer dans le Référentiel.

ADDENDUM 1 (9 février 2010): Parfois, l'attribution de propriétés du Modèle n'est pas assez. Il devrait y avoir pris des mesures à l'encontre du Modèle de Domaine en fonction des valeurs de Modèle de Vue. I. e., certaines méthodes doit être appelée sur le Modèle de Domaine. Probablement, il devrait y avoir une sorte de couche de Service d'Application qui s'étend entre le Contrôleur et le Domaine dans le but de traiter les Modèles de Vue...


Comment organiser ce code et où la placer à atteindre les objectifs suivants?

  • garder les contrôleurs mince
  • l'honneur de la SoC pratique
  • suivez Domain-Driven Design principes
  • être à SEC
  • à suivre ...

37voto

Omu Points 17372

J'utilise un IBuilder de l'interface et de mettre en œuvre à l'aide de la ValueInjecter

public interface IBuilder<TEntity, TViewModel>
{
      TEntity BuildEntity(TViewModel viewModel);
      TViewModel BuildViewModel(TEntity entity);
      TViewModel RebuildViewModel(TViewMOdel viewModel); 
}

... (mise en œuvre) RebuildViewModel appelle juste BuildViewModel(BuilEntity(viewModel))

[HttpPost]
public ActionResult Update(ViewModel model)
{
   if(!ModelState.IsValid)
    {
       return View(builder.RebuildViewModel(model);
    }

   service.SaveOrUpdate(builder.BuildEntity(model));
   return RedirectToAction("Index");
}

//btw, je n'écris pas ViewModel je écrire parce que c'est beaucoup plus courte, mais que tout simplement pas vraiment important
j'espère que ça aide

7voto

PanJanek Points 3764

Des outils comme AutoMapper peut être utilisé pour mettre à jour un objet existant avec les données de la source de l'objet. Le contrôleur d'action pour la mise à jour pourrait ressembler à:

[HttpPost]
public ActionResult Update(MyViewModel viewModel)
{
    MyDataModel dataModel = this.DataRepository.GetMyData(viewModel.Id);
    Mapper<MyViewModel, MyDataModel>(viewModel, dataModel);
    this.Repostitory.SaveMyData(dataModel);
    return View(viewModel);
}

En dehors de ce qui est visible dans l'extrait ci-dessus:

  • L'envoi de données à la vue du modèle + validation se fait en ModelBinder (peut-être exended avec des liaisons personnalisées)
  • Gestion des erreurs (c'est à dire la capture de données d'accès exception jette par Dépôt) peut être fait par [HandleError] filtre

Contrôleur de l'action est assez mince et les préoccupations sont séparés: la cartographie sont les questions abordées dans AutoMapper de configuration, la validation se fait par ModelBinder et d'accès aux données par le Référentiel.

5voto

Sean Copenhaver Points 2070

Je tiens à dire que vous réutilisez le terme ViewModel pour les deux directions de l'interaction avec le client. Si vous avez lu assez ASP.NET MVC code dans la nature, vous avez probablement vu la distinction entre un ViewModel et un EditModel. Je pense que c'est important.

Un ViewModel représente toutes les informations nécessaires pour effectuer le rendu d'une vue. Cela pourrait inclure des données qui est rendu en statique non-interactive des lieux et également des données purement d'effectuer un contrôle de décider sur ce qu'est exactement le rendu. Un Contrôleur d'OBTENIR une action est généralement responsable de l'emballage jusqu'au ViewModel pour son point de Vue.

Un EditModel (ou peut-être un ActionModel) représente les données requises pour exécuter l'action de l'utilisateur voulais faire pour ce POST. Donc un EditModel est vraiment essayer de décrire une action. Ce sera probablement exclure certaines données à partir de ce Dernier et bien que liés, je pense qu'il est important de réaliser qu'ils sont en effet différents.

Une Idée

Qui dit que vous pouvez très facilement avoir une AutoMapper de configuration de Modèle -> ViewModel et un autre pour aller de EditModel -> Modèle. Puis les différentes actions du Contrôleur suffit d'utiliser AutoMapper. L'enfer de la EditModel pourraient avoir des fonctions de valider ses propriétés contre le modèle et l'application de ces valeurs pour le Modèle lui-même. C'est ne rien faire d'autre et que vous avez ModelBinders MVC à la carte à la Demande de la EditModel de toute façon.

Une Autre Idée

Au-delà que ce que je pensais récemment ce genre de travaux hors de l'idée d'un ActionModel est que ce que le client est l'affichage de retour pour vous est en fait la description de plusieurs actions de l'utilisateur effectué et pas juste une grosse boule de données. Ce serait certainement besoin d'un peu de Javascript, côté client, de gérer, mais l'idée est intrigante, je pense.

Essentiellement que l'utilisateur effectue des actions sur l'écran que vous avez présentée, Javascript serait de commencer à créer une liste d'objets d'action. Un exemple est, peut être, c'est à l'utilisateur une information sur les employés de l'écran. Ils mettent à jour le nom et ajouter une nouvelle adresse parce que l'employé a été récemment marié. Sous les couvertures de ce produit un ChangeEmployeeName et AddEmployeeMailingAddress objets d'une liste. L'utilisateur clique sur "Enregistrer" pour valider les modifications et vous soumettre la liste de deux objets, chacun contenant uniquement les informations nécessaires pour effectuer chaque action.

Vous avez besoin d'une plus intelligente ModelBinder puis celui par défaut mais bon sérialiseur JSON doit être en mesure de prendre soin de la cartographie du côté client, les objets d'action pour le côté serveur. Le côté serveur (si vous êtes dans un 2-tier de l'environnement) pourrait facilement avoir des méthodes qui ont terminé l'action sur le Modèle qu'ils travaillent avec. Ainsi, le Contrôleur de l'action se termine juste à l'obtention d'un Identifiant de l'instance du Modèle de pull et une liste d'actions à effectuer. Ou les actions que l'id d'eux pour les garder très distincte.

Alors peut-être quelque chose comme ceci est réalisée sur le côté serveur:

public interface IUserAction<TModel>
{
     long ModelId { get; set; }
     IEnumerable<string> Validate(TModel model);
     void Complete(TModel model);
}

[Transaction] //just assuming some sort of 2-tier with transactions handled by filter
public ActionResult Save(IEnumerable<IUserAction<Employee>> actions)
{
     var errors = new List<string>();
     foreach( var action in actions ) 
     {
         // relying on ORM's identity map to prevent multiple database hits
         var employee = _employeeRepository.Get(action.ModelId);
         errors.AddRange(action.Validate(employee));
     }

     // handle error cases possibly rendering view with them

     foreach( var action in editModel.UserActions )
     {
         var employee = _employeeRepository.Get(action.ModelId);
         action.Complete(employee);
         // against relying on ORMs ability to properly generate SQL and batch changes
         _employeeRepository.Update(employee);
     }

     // render the success view
}

Que fait vraiment l'affichage d'action assez générique, puisque vous vous appuyez sur votre ModelBinder pour vous le bon IUserAction instance et votre IUserAction instance de la bonne logique elle-même, ou (plus probablement) appel dans le Modèle à l'info.

Si vous étiez dans un 3 niveau de l'environnement de la IUserAction pourrait juste être simple Otd être tiré à travers la frontière et réalisée de la même méthode sur l'application de la couche. En fonction de comment vous le faites que la couche peut être divisée en place très facilement et restent dans une transaction (ce qui vient à l'esprit est Agathe de requête/réponse et de prendre avantage de la DI et de NHibernate de la carte d'identité).

De toute façon je suis sûr que ce n'est pas une idée parfaite, il aurait besoin d'un peu de JS côté client à gérer, et je n'ai pas été capable de faire un projet qui reste encore à voir comment elle se déroule, mais le post a été en essayant de penser à comment faire pour y aller et revenir de nouveau, alors j'ai pensé que je voudrais donner à mes pensées. J'espère que cela aide, et j'aimerais entendre d'autres façons de gérer les interactions.

0voto

oguzh4n Points 314

Vous n'avez pas besoin de cartographie viewmodel de domaine parce que votre viewmodel peut être créé plus de modèle de domaine. Viewmodel optimisée pour l'écran de (ui) et les différents à partir du modèle de domaine.

http://lostechies.com/jimmybogard/2009/06/30/how-we-do-mvc-view-models/

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X