1 votes

LINQ to SQL valide tous les champs, et ne s'arrête pas seulement au premier champ en échec

Je viens de commencer à utiliser les classes LINQ to SQL, et j'aime beaucoup la façon dont cela m'aide à écrire du code lisible. Dans la documentation, les exemples typiques indiquent que pour faire une validation personnalisée, vous créez une classe partielle comme suit: :

partial class Customer 
{
    partial void OnCustomerIDChanging(string value)
    {
        if (value=="BADVALUE") throw new NotImplementedException("CustomerID Invalid");
    }
}

Et de même pour les autres champs... Et ensuite dans le codebehind, je mets quelque chose comme ceci pour afficher le message d'erreur et garder l'utilisateur sur la même page afin de corriger l'erreur.

    public void CustomerListView_OnItemInserted(object sender, ListViewInsertedEventArgs e)
{
    string errorString = "";
    if (e.Exception != null)
    {
      e.KeepInInsertMode = true;
      errorString += e.Exception.Message;
      e.ExceptionHandled = true;
    }
    else errorString += "Successfully inserted Customer Data" + "\n";
    errorMessage.Text = errorString;
}

D'accord, c'est facile, mais ensuite il arrête de valider le reste des champs dès que la première exception est lancée ! Ce qui veut dire que si l'utilisateur a fait plus d'une erreur, il ne sera notifié que de la première erreur. Existe-t-il un autre moyen de vérifier toutes les entrées et de montrer les erreurs pour chacune d'entre elles ? Toute suggestion sera appréciée, merci.

1voto

Steven Points 56939

Cela ressemble à un travail pour le Bloc d'application pour la validation de la bibliothèque d'entreprise (VAB). Le VAB a été conçu pour renvoyer toutes les erreurs. En outre, il ne lève pas d'exception, de sorte que vous pouvez simplement lui demander de valider le type pour vous.

Lorsque vous décidez d'utiliser le VAB, je vous conseille de ne pas utiliser les méthodes OnXXXChanging et OnValidate de LINQ to SQL. Il est préférable de surcharger la méthode SubmitChange(ConflictMode) de la classe DataContext pour faire appel à l'API de validation du VAB. Cela permet de garder votre logique de validation en dehors de vos entités commerciales, ce qui permet de garder vos entités propres.

Regardez l'exemple suivant :

public partial class NorthwindDataContext
{
    public ValidationResult[] Validate()
    {
        return invalidResults = (
            from entity in this.GetChangedEntities()
            let type = entity.GetType()
            let validator = ValidationFactory.CreateValidator(type)
            let results = validator.Validate(entity)
            where !results.IsValid
            from result in results
            select result).ToArray();            
    }

    public override void SubmitChanges(ConflictMode failureMode)
    {
        ValidationResult[] this.Validate();

        if (invalidResults.Length > 0)
        {
            // You should define this exception type
            throw new ValidationException(invalidResults);
        }

        base.SubmitChanges(failureMode);
    }

    private IEnumerable<object> GetChangedEntities()
    {
        ChangeSet changes = this.GetChangeSet();

        return changes.Inserts.Concat(changes.Updates);
    }
}

[Serializable]
public class ValidationException : Exception
{
    public ValidationException(IEnumerable<ValidationResult> results)
        : base("There are validation errors.")
    {
        this.Results = new ReadOnlyCollection<ValidationResult>(
            results.ToArray());
    }

    public ReadOnlyCollection<ValidationResult> Results
    {
        get; private set; 
    }
}

L'appel de la méthode Validate() renverra une collection de toutes les erreurs, mais plutôt que d'appeler Validate(), j'appellerais simplement SubmitChanges() lorsque vous êtes prêt à persister. SubmitChanges() vérifiera maintenant les erreurs et lèvera une exception si l'une des entités n'est pas valide. Comme la liste des erreurs est envoyée à l'exception ValidationException, vous pouvez itérer sur les erreurs plus haut dans la pile d'appels, et les présenter à l'utilisateur, comme suit :

try
{
    db.SubmitChanges();
}
catch (ValidationException vex)
{
    ShowErrors(vex.ValidationErrors);
}

private static void ShowErrors(IEnumerable<ValidationResult> errors)
{
    foreach(var error in errors)
    {
        Console.WriteLine("{0}: {1}", error.Key, error.message);
    }
}

Lorsque vous utilisez cette approche, vous vous assurez que vos entités sont toujours validées avant de les enregistrer dans la base de données.

Ici est un bon article qui explique comment intégrer VAB avec LINQ to SQL. Vous devez absolument le lire si vous voulez utiliser VAB avec LINQ to SQL.

0voto

Lasse V. Karlsen Points 148037

Pas avec LINQ. Vous devriez probablement valider l'entrée avant en le donnant à LINQ.

Ce que vous voyez est un comportement naturel avec des exceptions.

0voto

Slabo Points 307

J'ai trouvé une solution. Au lieu de lancer une exception au premier échec de validation, je stocke un message d'erreur dans une classe avec une variable statique. Pour ce faire, j'étend la classe DataContext comme suit: :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

/// <summary>
/// Summary description for SalesClassesDataContext
/// </summary>
public partial class SalesClassesDataContext
{
    public class ErrorBox
    {
        private static List<string> Messages = new List<string>();
        public void addMessage(string message)
        {
            Messages.Add(message);
        }
        public List<string> getMessages() 
        {
            return Messages;
        }
    }
}

dans les classes correspondant à chaque table, j'hériterais de la classe nouvellement définie comme ceci : :

public partial class Customer : SalesClassesDataContext.ErrorBox

seulement dans la fonction OnValidate je lancerais une exception au cas où le nombre d'erreurs ne serait pas égal à 0. Ainsi, il n'y a pas de tentative d'insertion, et l'utilisateur reste sur la même page de saisie, sans perdre les données qu'il a saisies.

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