118 votes

Les données sont nulles. Cette méthode ou propriété ne peut pas être appelée sur des valeurs nulles.

Je travaille sur une application où l'on peut obtenir des informations sur des films à partir d'une base de données ainsi que ajouter, mettre à jour et supprimer les films. Dans la base de données, j'ai trois tables (Film, Genre et MovieGenre <- stocke les films et leur(s) genre(s)). Tout fonctionne bien sauf une chose, et c'est lorsque un film n'a pas de genres (ce qui devrait être possible).

Le problème se produit dans la méthode ci-dessous, et l'exception suivante est levée: Les données sont nulles. Cette méthode ou propriété ne peut pas être appelée sur des valeurs nulles.

La raison (bien sûr) est que la procédure stockée retourne null car le film n'a pas de genres, mais je n'arrive pas à comprendre comment éviter que cette exception soit levée. Comme je l'ai dit, il devrait être possible de stocker un film sans stocker aucune information sur son/ses genre(s).

La méthode:

public List GetMovieGenrebyMovieID(int movieID) {

    using (SqlConnection conn = CreateConnection()) {
        try {

            SqlCommand cmd = new SqlCommand("dbo.usp_GetMovieGenreByMovieID", conn);
            cmd.CommandType = CommandType.StoredProcedure;

            cmd.Parameters.AddWithValue("@MovieID", movieID);

            List movieGenre = new List(10);

            conn.Open();

            using (SqlDataReader reader = cmd.ExecuteReader()) {

                int movieGenreIDIndex = reader.GetOrdinal("MovieGenreID");
                int movieIDIndex = reader.GetOrdinal("MovieID");
                int genreIDIndex = reader.GetOrdinal("GenreID");

                while (reader.Read()) {

                    movieGenre.Add(new MovieGenre {
                        MovieID = reader.GetInt32(movieIDIndex),
                        MovieGenreID = reader.GetInt32(movieGenreIDIndex),
                        GenreID = reader.GetInt32(genreIDIndex)
                    });
                }
            }

            movieGenre.TrimExcess();

            return movieGenre;
        }
        catch {
            throw new ApplicationException();
        }
    }
}

La procédure stockée:

ALTER PROCEDURE usp_GetMovieGenreByMovieID
@MovieID int
AS
BEGIN
    BEGIN TRY
        SELECT m.MovieID, g.GenreID, mg.MovieGenreID, g.Genre
        FROM Movie AS m
        LEFT JOIN MovieGenre AS mg
            ON m.MovieId = mg.MovieID
        LEFT JOIN Genre AS g
            ON mg.GenreID = g.GenreID
        WHERE m.MovieID = @MovieID
    END TRY
    BEGIN CATCH
        RAISERROR ('Erreur lors de la tentative de récupération du/des genre(s)',16,1)
    END CATCH
END

108voto

kaj Points 2747

Vous ne devriez pas essayer de convertir les valeurs nulles du proc en entiers - donc avant de créer l'instance MovieGenre, vous devez vérifier les champs nullable en utilisant la méthode SqlDataReader.IsDBNull:

http://msdn.microsoft.com/fr-fr/library/system.data.sqlclient.sqldatareader.isdbnull.aspx

En supposant que GenreID et MovieGenreID sont des entiers nullable, vous pourriez faire quelque chose comme:

movieGenre.Add(new MovieGenre {
  MovieID = reader.GetInt32(movieIDIndex),
  MovieGenreID = reader.IsDBNull(movieGenreIDIndex) ? null : reader.GetInt32(movieGenreIDIndex),
  GenreID = reader.IsDBNull(genreIDIndex) ? null : reader.GetInt32(genreIDIndex)
});

73voto

Rosdi Kasim Points 3588

Cette erreur se produit immédiatement après que j'ai activé la fonctionnalité nullable de C# 8 dans mon projet Entity Framework Core 3.1.

La solution consiste à changer vos propriétés d'entité pour leurs homologues nullable. Par exemple,

Changer de :

public class Person {
  public int Id { get; set; }
  public string Name { get; set; }
  public string Address { get; set; }
}

À :

public class Person {
  public int Id { get; set; }
  public string Name { get; set; }
  public string? Address { get; set; }  // changer 'Address' en string nullable car il est nullable dans la base de données
}

16voto

Amr ElGarhy Points 12696

Dans mon cas, j'utilisais EF Core et le problème était que le champ était nullable dans la base de données mais dans le ModelCreating, il était requis comme ceci :

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
   modelBuilder.Entity(entity =>
   {
      entity.Property(e => e.Details)
                    .IsRequired()
                    .HasMaxLength(250);
   }
}

J'ai supprimé IsRequired() et ça a fonctionné correctement.

Mise à jour quelques jours plus tard, J'ai eu le même problème, un champ de type chaîne de caractères qui n'acceptait pas la valeur null dans la base de données.

15voto

Kaf Points 16395

Modifiez votre déclaration de sélection comme suit pour gérer le problème de nullité.

SELECT ISNULL(m.MovieID,0) AS MovieID, 
       ISNULL(g.GenreID,0) AS GenreID, 
       ISNULL(mg.MovieGenreID,0) AS MovieGenreID,
       ISNULL(g.Genre,'') AS Genre
FROM --reste de votre requête...

9voto

PopeDarren Points 54

Je réalise que c'est ancien, mais j'ai juste eu ce problème avec EF Core dans .net 6.

Même si les chaînes de caractères sont nullable (dans les anciennes versions de .net) et que Entity Framework a même créé mes objets à partir de la table existante avec le type string, j'ai dû changer le type en string? pour récupérer des données lorsque les données étaient nulles (dans les colonnes qui étaient nullable).

Pour les colonnes qui sont nullable dans vos tables de base de données :

incorrect :

public string Decision { get; set; }

correct :

public string? Decision { get; set; }

Je pensais avoir un problème avec l'injection de dépendance. Il s'avère que c'était Entity Framework Core et c'était une correction simple.

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