1
votes

Entity Framework: comment détecter toute erreur

J'essaie d'insérer des données dans une table SQL Server qui a beaucoup de contraintes non nulles :

try
{
   _context.SaveChanges();
}
catch (Exception e)
{
}


try
{
   _context.SaveChanges();
}
catch
{
}

Code EF: strong >

try
{
   _context.SaveChanges();
}
catch (DbUpdateException e)
{
}

Lors de la tentative d'ajout de données dans la table, le code manque de colonnes, il ne parvient donc pas à s'insérer dans la base de données. Je ne savais pas à ce sujet, et je n'ai pas reçu d'erreurs 'NOT NULL', comme je le verrais dans la base de données SQL.

var source = new Customer();

source.FirstName = "Joe";  // missing Last Name and Address
_context.Customer.Add(source);

J'ai donc ajouté le code suivant. Cela résout le problème, mais comment le faire échouer en cas d'erreur de base de données, de concurrence, de types de données incorrects, etc.

public virtual DbSet<Customer> Customer { get; set; }
modelBuilder.Entity<Customer>(entity =>
{
    entity.Property(e => e.FirstName)
        .HasMaxLength(255)
        .IsRequired()
        .IsUnicode(false);

    entity.Property(e => e.LastName)
            .HasMaxLength(255)
            .IsRequired()
            .IsUnicode(false);

    entity.Property(e => e.AddressLine)
            .HasMaxLength(255)
            .IsRequired()
            .IsUnicode(false);
  });

Les éléments suivants ne fonctionnaient pas: Méthode 1 et 2: lorsque celles-ci ont été implémentées, l'erreur non nulle ne s'affichait plus comme nous le voulions.

CREATE TABLE [dbo].[Customer]
(
    [CustomerId] [int] IDENTITY(1,1) NOT NULL,
    [FirstName] [varchar](255) NOT NULL,
    [LastName] [varchar](255) NOT NULL,
    [AddressLine] [varchar](255) NOT NULL
    CONSTRAINT [PK_Customer] PRIMARY KEY CLUSTERED ([CustomerId] ASC)
 )


0 commentaires

4 Réponses :


0
votes
try {
   var source = new Customer();
   source.FirstName = "Joe";

   _context.Customer.Add(source);
   _context.SaveChanges();
}
catch (Exception ex) {
   // ...
}

0 commentaires

0
votes

Vous pouvez vérifier un type de votre exception dans le bloc catch pour obtenir un message d'exception exact comme

try
{
    //Your code here
}
catch (DbEntityValidationException de_ex)
{
    //Exception thrown from System.Data.Entity.DbContext.SaveChanges when validating entities fails.
}
catch (DbUnexpectedValidationException du_ex)
{
    //Exception thrown from System.Data.Entity.DbContext.GetValidationErrors when an
    //exception is thrown from the validation code.
}
catch (Exception ex)
{
    //All remaining exception here 
}

Ou vous pouvez utiliser un bloc catch différent par type d'exception

try
{
    //Your code here
}
catch (Exception ex)
{
    if (ex.GetType() == typeof(DbEntityValidationException))
    {
        //Exception thrown from System.Data.Entity.DbContext.SaveChanges when validating entities fails.
    }
    else
    if (ex.GetType() == typeof(DbUnexpectedValidationException))
    {
        //Exception thrown from System.Data.Entity.DbContext.GetValidationErrors when an
        //exception is thrown from the validation code.
    }
    else
    {
        //All remaining exception here 
    }
}


2 commentaires

Je voulais attraper toutes les exceptions dans un scoop sans en énumérer aucune, y a-t-il quand même? Merci


signifie que vous voulez obtenir une exception de n'importe quel type dans un seul bloc catch et sans sinon? alors la classe parent Excpetion fait tout cela pour vous



4
votes

DbContext.SaveChanges décrit les exceptions auxquelles vous pouvez vous attendre. Décidez quelles exceptions vous voulez attraper et celles qui ne le sont pas.

Si vous n'êtes pas certain des exceptions que vous obtenez dans quelles situations, utilisez votre débogueur et du code de test pour savoir à quelles exceptions vous pouvez réellement vous attendre:

try
{
   _context.SaveChanges();
}
catch (DbUpdateException e)
{
    // handle the update exception
}
catch (DbEntityValidationException e)
{
    // handle the entity validation exception
}
catch (...)

Lorsque vous sachez à quelles exceptions vous pouvez vous attendre et lesquelles vous pouvez vraiment gérer, écrivez votre code final:

// TODO: create one of your error conditions
try
{
   _context.SaveChanges();
}
catch (Exception e)
{
    Console.WriteLine(e.GetType()); // what is the real exception?
}

Vous n'attraperez probablement pas System.NotSupportedException, votre code devrait être tel qu'il ne doit utiliser que les instructions LINQ prises en charge.

Optimisation

Gardez à l'esprit que les DbSets de votre DbContext représentent les tables dans votre base de données. Les classes dans les DbSets représentent une ligne dans la table: les propriétés non virtuelles représentent les colonnes de la table, les relations entre les tables sont représentées comme des propriétés virtuelles.

Vous conçu ces tables de base de données parce que vous vouliez résoudre un problème. Apparemment, dans votre solution, il était important que FirstName / LastName, etc. ne soit pas nul.

Vous allez probablement envelopper l'utilisation de votre DbContext dans une classe qui cache que vous utilisez le framework d'entité pour conserver vos données, à la place de, par exemple Dapper, ou toute méthode de niveau inférieur pour interroger et mettre à jour les données.

Très souvent, cette classe wrapper est appelée une classe Repository : les utilisateurs de votre Repository ne sais pas, et ne se soucie vraiment pas, comment et où vous enregistrez vos données: SQL? Mongo? Peut-être même un fichier CSV?

L'avantage d'avoir une classe Repository est que si vous décidez de changer la disposition de votre tableau, ou si vous décidez de changer l'un de vos requêtes dans une procédure stockée, ou si vous décidez de stocker vos données dans un CSV, les changements seront minimes et les utilisateurs ne remarqueront même pas le changement

Dans votre référentiel, vous aurez des fonctions pour interroger les personnes, pour ajouter / supprimer / mettre à jour une personne, etc. Vous avez décidé plus tôt que votre solution ne devrait pas accepter de personnes avec des noms nuls.

Votre solution ne dépend pas de la manière dont vos données sont enregistrées. Par conséquent, votre solution ne devrait pas dépendre du fait que votre référentiel vérifie si vos noms sont nuls ou nt.

Pensez à vérifier la validité des données avant d'appeler SaveChanges . Dans ce cas: vérifiez si le prénom, le nom etc. ne sont pas nuls. Votre code

  • paraître plus propre: moins de traitement des exceptions lancées par des parties en dehors de votre champ d'application
  • plus facile à lire: les lecteurs n'auront pas à deviner ce qui se passe si les données sont nulles,
  • plus facile à tester: votre code de test peut utiliser un référentiel simulé simple sans vérification nulle
  • meilleure maintenance: si vous décidez d'autoriser l'ajout de personnes sans prénom, votre modèle de base de données ne change pas, seulement votre classe de référentiel


0 commentaires

2
votes

En utilisant le code suivant, vous pouvez créer un message plus convivial pour DbEntityValidationException:

try
{
   _context.SaveChanges();
}
catch (DbEntityValidationException dbEx)
{
    var sb = new StringBuilder();
    foreach (var validationErrors in dbEx.EntityValidationErrors)
    {
        foreach (var validationError in validationErrors.ValidationErrors)
        {
           sb.AppendLine(string.Format("Property: {0} Error: {1}",
           validationError.PropertyName,validationError.ErrorMessage));
        }
     }
     throw new Exception(sb.ToString(), dbEx);
}

Ensuite, vous pouvez attraper cette nouvelle Exception au niveau supérieur; pour attraper d'autres exceptions, vous pouvez utiliser des blocs catch séparés.


0 commentaires