2014-04-30 3 views
0

J'ai une propriété "Identification" ajoutée par l'utilisateur qui ne doit pas être dupliquée. (différent de l'identifiant de base de données).Ignorer la recherche de doublons pour des propriétés spécifiques lors de la modification du modèle

J'ai ajouté la méthode suivante à mon ViewModel:

public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) 
     { 
      GearContext db = new GearContext(); 
      if (db.Items.Where(p => p.Identification == this.Identification).Count() > 0) 
      { 
       yield return new ValidationResult("Identification already in use, please chose a different one. ", new[] { "Identification" }); 
      } 
     } 

Le problème est que cela me empêche de modifier mon modèle. Je voudrais que cette validation se produise seulement quand une nouvelle entrée est créée, pas sur éditer.

J'ai essayé le type d'édition suivante dans mon contrôleur:

if (ModelState.IsValid) 
      { 
       var item = db.Items.Find(viewModel.ItemId); 
       Mapper.Map<ItemViewModel, Item>(viewModel, item); 
       if (TryUpdateModel(item, null, null, new string[] { "Identification" })) 
       { 
        db.SaveChanges(); 
        return RedirectToAction("Index"); 
       } 


      } 

aussi essayé sans le "TryUpdateModel" du tout (simple, viewmodel => modèle et db.save). J'ai pensé à implémenter la méthode de validation dans mon contexte DB et l'exécuter uniquement sur item.State == EntityState.Added mais je crois que je n'ai pas accès aux propriétés du modèle édité ici.

+0

Ne serait-il pas plus facile d'avoir une identification dans le cadre d'une clé unique sur la table pertinente et de laisser tout cela au SGBD? Même si vous implémentez cela dans MVC, une application de console ou un service Windows pourrait encore casser cette logique. L'avoir dans la DB signifie que rien ne peut. – barrick

+0

Est-il possible de définir une clé unique avec du code en premier? Aussi, n'aurais-je pas le même problème? Je me sens comme c'est la façon dont je mets à jour mon modèle qui pourrait être faux (il ne devrait pas toucher Identification/Id du tout). –

+0

Ce n'était certainement pas possible auparavant; vous voudrez peut-être vérifier EF6 pour voir si cela a été changé. Cependant, pour rester dans MVC, avez-vous des vues Create et Edit séparées? Vraisemblablement, Si tel est le cas, ayez des modèles de vue séparés pour chacun d'entre eux et utilisez le contrôleur pour créer des instances de ceux-ci lorsque la requête GET pertinente entre en jeu. Le modèle Create peut alors contenir cette validation alors que le modèle Edit peut l'avoir comme propriété immuable. besoin de la vérification. – barrick

Répondre

1

Pour éviter que l'élément en cours d'édition ne déclenche une erreur de validation, ajoutez une vérification de l'ID à la requête que vous utilisez. à-dire modifier cette ligne:

if (db.Items.Where(p => p.Identification == this.Identification).Count() > 0)

à ceci:

if (db.Items.Where(p => p.ID != this.ID && p.Identification == this.Identification).Count() > 0)

En aparté, je voudrais aussi changer .Count() > 0-.Any() de sorte que la requête recherchera pas plus de 1 enregistrement

Aussi, je pense vraiment que vous devriez vous pencher sur la mise en œuvre dans le DbContext pour éviter de contaminer la classe Modèle avec le DbContext. La façon de le faire est décrite ici: https://stackoverflow.com/a/18736484/150342

+0

Cela fonctionne parfaitement. Utilisant aussi .Any() au lieu de Count() maintenant. Je vais regarder dans le lien que vous avez posté aussi. Merci! –

0

Ce que vous pouvez faire est de changer votre méthode IValidatableObject pour lui faire prendre une collection. Quelque chose comme ça

public ICollection<IValidatableObject> Validations { get; set; } 

public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) 
{ 
    var valid = Enumerable.Empty<ValidationResult>(); 

    if (Validations != null) 
    { 
     valid = Validations.Aggregate(valid, (current, validate) => current.Concat(validate.Validate(validationContext))); 
    } 
    return valid; 
} 

Vous pouvez désormais joindre à la collection des validations Validations que l'interface IValidatableObject appellera. Lors de l'ajout, vous pouvez ajouter votre chèque en double. Lorsque vous retouchez le message ou ajoutez un contrôle de validation différent. Cela dit, je pense que les champs clés en double devraient être la responsabilité de la base de données et non la méthode de validation. Même avec cette vérification, il est toujours possible que vous ayez des doublons. La vérification IValidatableObject est effectuée avant l'envoi des données à SQL. Vous pouvez donc avoir deux entités avec la même clé en même temps, et les deux passeront et les deux seront ajoutées à SQL. Si vous voulez vraiment vous assurer que vous aurez besoin de passer outre la méthode de dbcontexts

public override int SaveChanges() 
{ 
    var results = base.SaveChanges(); 

    // Run validation again for adds 
    PostValidation(); 

    return results; 
} 

Tant que vous êtes dans une transaction, il n'a pas été commise encore et vous pouvez vérifier SQL pour les clés doublons maintenant et si oui renvoie une erreur et annule la transaction.

+0

Merci pour la réponse. Quelques informations précieuses que j'utiliserai très probablement à l'avenir. J'ai accepté la réponse de Colin parce que c'est très simple. –

Questions connexes