11
votes

Utilisation de MVC et de Nibernate fluide, comment valider des champs uniques sur mon viewModel avant que je les lie à mon objet de domaine et à les sauvegarder?

J'ai un site Web où je permet aux utilisateurs de créer de nouveaux enregistrements de pièce. J'essaie de comprendre le meilleur moyen de valider des champs spécifiques pour l'unicité. Je tiens à vous assurer que quelqu'un n'essaie pas d'ajouter une partie avec PARNOMBER 1234 si ce nombre de personnes existe déjà sur une autre partie.

L'application Web utilise ASP.NET MVC avec NHibernate fluide pour mapper mes objets dans la base de données. J'utilise la validation du château sur mes modèles de vue pour des choses comme Validatenonempty, validaterange, etc. Dois-je utiliser VALIDALEZ Méthode pour interroger le référentiel pour voir si ce numéro de pièce existe déjà? Quelque chose ne se sent pas dû à utiliser mon référentiel sur le point de vue. P>

serait-il préférable pour moi de placer cette logique sur l'action du contrôleur? Cela ne semble pas juste parce que je m'attends à ce que mon point de vue soit déjà validé au point (pendant le modèleBind). P>

ou peut-être que ce n'est pas ce qui est ci-dessus. Merci pour toute aide sur celle-ci. P>

mise à jour forte> Ok, je ne sais pas si cela aidera, mais voici ce que mes actions de sauvegarde ressemblent à une action typique de créer dans mon projet: P>

public ActionResult Create(PartViewModel viewModel)
{
 //I think I'd like to know if its Valid by this point, not on _repository.Save
 if(ModelState.IsValid)
 {
    try
    {
        var part = _partCreateViewModelMap.MapToEntity(viewModel);

        _repository.Save(part);
        return Redirect("~/Part/Details/" + part.Id);
    }
    catch (Exception e)
    {
        // skip on down...
    }
 }

 // return view to edit 
 return View(viewModel);
}


2 commentaires

N'oubliez pas qu'un autre utilisateur pourrait ajouter une partie avec la pièce numéro 1234 après avoir effectué la vérification du premier utilisateur essayant d'ajouter cette pièce, avant d'avoir mis à jour la base de données.


@Ian, c'est un grand point. Il n'y aura que quelques utilisateurs avec la responsabilité de l'ajout de pièces. À ce stade, je suis beaucoup plus inquiet pour les pièces en double en général que les pièces en double en même temps. Il y a une probabilité beaucoup plus faible de cela se produisant mais c'est une grande observation.


6 Réponses :


0
votes

Je n'ai pas de réponse à votre question, mais vous pouvez vérifier le site de SharpRarCitecture.net. Il contient quelques meilleures pratiques pour ASP.NET MVC et NHibernate. De plus, je peux vous recommander de vérifier le projet XVAL et les didacticiels sur la validation des validateurs d'annotation de données


1 commentaires

@hodzanassredin, merci - j'utilise le cadre Xval. Cela est juste assis entre la validation du côté serveur et le cadre de validation du client (JQuery). XVal n'a rien vraiment à titre de validation à distance, alors je peux envisager l'article de Adrian Grigore à ce sujet.



1
votes

On m'a demandé cette question plusieurs fois. Mes amis étaient inquiets de savoir s'ils peuvent effectuer un accès aux données à partir du code de validateur. La réponse est simple. Si vous avez besoin de faire cela, vous devriez le faire. Habituellement, nous devons faire de tels contrôles à chaque niveau d'abstraction. Et après tous les chèques, vous devriez être prêt à attraper une exception, causée par une violation des contraintes uniques.


3 commentaires

Merci pour votre réponse. Je ne pense pas à attraper une exception, je pense que je veux voir si cela existe avant que j'essaie de l'engager. Ce serait une erreur de validation provoquant la fausse erreur de modèleStat.isvalid - pas une exception.


La validation ne garantit pas la réussite de l'opération.


accepté parce que comme vous le suggérez, «vous devriez le faire» est ce que j'ai fait. Cela fonctionne comme demandé dans la question et cela a bien fonctionné. Merci.



0
votes

J'ai trouvé la solution qui fonctionne pour moi est de

1.) Demandez si l'entité est valide pour exécuter votre travail de validation.
2.) Une fois que cela est terminé, vous devez avoir quelque chose sur votre objet à montrer qu'il est valide ou non (dans mon cas, j'utilise un concept CSLA comme "Règles brisées"). 3.) Si vous avez quelque chose comme ça, vous pouvez vérifier que l'objet est valide avant que NHibernate essaie de le persister comme indiqué ci-dessous. P>

Le seul problème avec cette approche est que vous devez mettre en œuvre une interface sur chaque entité nécessitant une validation. Si vous pouvez vivre avec cela, il arrêtera NHibernate de persister les modifications d'un objet qui n'est pas valide selon vos règles. P>

using System;
using NHibernate;
using NHibernate.Event;
using Validation.Entities.Interfaces;
using Persistence.SessionBuilder;

namespace Persistence.Validation
{
    public class ValidationEventListener : IPreInsertEventListener, IPreUpdateEventListener
    {

        public bool OnPreInsert(NHibernate.Event.PreInsertEvent @event)
        {
            var entityToInsert = @event.Entity as IBusinessBase;

            if (entityToInsert != null)
            {
                if (entityToInsert.BrokenRules != null)
                {
                    RollbackTransactionBecauseTheEntityHasBrokenRules();
                }
            }

            return false;
        }

        public bool OnPreUpdate(NHibernate.Event.PreUpdateEvent @event)
        {
            var entityToUpdate = @event.Entity as IBusinessBase;

            if (entityToUpdate != null)
            {
                if (entityToUpdate.BrokenRules != null)
                {
                    RollbackTransactionBecauseTheEntityHasBrokenRules();
                }
            }

            return false;
        }

        private void RollbackTransactionBecauseTheEntityHasBrokenRules()
        {
            try
            {
                ISession session = SessionBuilderFactory.GetBuilder().CurrentSession;

                if (session != null)
                {
                    session.Transaction.Rollback();
                }
            }
            catch (Exception ex)
            {
                //this will force a rollback if we don't have a session bound to the current context 
                throw new NotImplementedException();
            }
        }
    }
}


3 commentaires

@Toran billups, merci pour votre réponse. Je ne pense pas que cela résout le problème uniquement parce que ma question est plus sur lorsque / où valider les "BrokersRules" qu'il s'agit de la manipuler sur la préservation ou la préparation. Je pense que je veux savoir si cela va être un commit valide avant d'essayer de l'engager. Ou est-ce le mauvais moyen de regarder ça? Consultez ma mise à jour s'il vous plaît.


Comprendu, dans ce cas, je vous recommanderais de déplacer tout le code de votre contrôleur ci-dessus vers un service ou une couche de façade qui serait chargée de demander au modèle si l'état est valide, puis effectuez le travail de sauvegarde (s'il est valide) . La raison pour laquelle mon code est toujours requis est que le NHibernate persistera (ou essaie de persister) les changements, que vous appelez explicitement "_répository.save (partie)" - et à cause de cela, un type d'écouteur d'événement de validation est nécessaire pour arrêter ceci la persistance de se produire.


@Toran, merci encore - ce code n'est pas nécessaire si je peux en valider le modèle de modèle d'abord. Vous pouvez voir par ma mise à jour que je teste ModelState.isvalid avant d'essayer de l'enregistrer. Peut-être que la solution consiste à appeler cette nouvelle couche de type validationsVice et à passer dans le référentiel du contrôleur. Cela permettrait une injection de dépendance et je pourrais le faire avant que les erreurs de validation de «if (modelstate.isvalid)« si (modelstate.isvalid) puissent toujours bouillir à la fenêtre. Peut-être que je passe dans le modèle de modèle ou d'erreurs au nouveau service.



1
votes

Si vous définissez une contrainte unique dans la base de données, alors pourquoi ne pas déléguer la responsabilité de vérifier si une valeur unique existe déjà dans la base de données? Utilisation de NHibernate, vous pouvez utiliser l'interface Nhibernate.Exception.isqlexceptionConverter code> pour capturer et transformer des erreurs connues concernant des violations de contraintes. Vous pouvez également utiliser NHibernate.Exception.iviolatedConstrynTnameExTracter code> Confidentiers (voir NHibernate.Exception.TemplatedViolateDnampleNtNameExTracter code>) Pour obtenir les détails de votre base de données et la transformer en user- Message sympathique, reconditionnement comme une exception de validation de votre cheîcheur et attrapez-la dans le contrôleur correspondant.

Exemple d'un convertisseur d'exception rapide et sale rapide et très spécifique de l'un de mes projets: p> xxx pré>

configuré via le Web.config / NHibernate-configuration / Session-Factory Code> Elément de la propriété: p>

<property name="sql_exception_converter">csl.NHibernate.ConstraintViolationExceptionConverter, csl</property>


1 commentaires

Merci @rabid mais je ne sais pas comment cela s'applique à ma situation. Si NHibernate me fournit un moyen de créer des colonnes uniques en dehors de la clé primaire du GUID, ce serait bien de savoir, mais j'essaie définitivement d'éviter de faire sauvegarder la base de données - ce n'est vraiment pas validation, son erreur manutention



1
votes

J'ai généralement placé une couche de service entre mes contrôleurs et mes référentiels.
La couche de service gérerait alors la validation et les appels au référentiel.

Ensuite, s'il y a une erreur de validation dans la couche de service, je jette une exception personnalisée, attrapez-la dans le contrôleur et injectez les erreurs dans l'état modèle.


3 commentaires

@Citizenbane, merci pour votre réponse. Je cherche spécifiquement à conserver la possibilité d'ajouter un message d'erreur à l'égard de la château.commeurs.validator. On dirait que je devrais le faire avant de frapper le contrôleur afin que je retourne immédiatement le modèle de visualisation pour éditer


@shanabus Je ne connais pas le château.chPonents.validator, mais après avoir effectué une recherche rapide Google, j'ai trouvé ceci: Altinoren.com/... hth


@CITEZENBANE, j'ai déjà eu le château filaire avec un validationRunner et des attributs sur mes propriétés du modèle de vue. Mes questions concernent la meilleure façon de valider des données uniques dans le référentiel. Ce lien ne traite pas du tout.



0
votes

Je dirais que cela compte sur votre architecture. Avec les applications MVC que j'ai faites dans le passé, nous abstraits de la matière de domaine loin du web, nous utilisons naturellement une injection de dépendance pour éviter les dépendances difficiles.

En ce qui concerne la validation du modèle lorsque vous vous trouvez dans l'acte de le lier, vous pouvez facilement utiliser le service, le référentiel ou tout ce que vous avez suivant dans votre architecture dans une méthode ValidatElation. Je pense que la question monte de quoi de cette dépendance.

Si je me souviens bien, vous pouvez créer votre propre liant personnalisé qui utilisera votre framework d'injection de dépendance pour brancher tous les services de votre modèle de validation lorsque vous le créez, appelez le liant par défaut de MVC à remplir l'objet, puis appelez à l'objet. Cadre de validation du château pour faire la validation. Ce n'est pas une solution entièrement pensé, mais j'espère que cela provoque quelques idées.


1 commentaires

Merci @Sean Copenhaver, cela provoque quelques idées. Je ne voulais pas regarder dans un classeur personnalisé simplement parce que chaque entité de domaine a une propriété différente qui sera utilisée pour valider l'unicité. Peut-être que je combine un liant personnalisé avec un attribut personnalisé comme [MustBetunique] de cette façon, le liant sait quoi traiter.