web-dev-qa-db-fra.com

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 les films à partir d'une base de données et ajouter, mettre à jour et supprimer les films. Dans la base de données, j'ai trois tableaux (Movie, Genre et MovieGenre <- stocke les films et leurs genres). Tout fonctionne bien à part une chose, et c'est quand 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 le sproc retourne null parce que le film n'a pas de genres, mais je ne peux pas comprendre comment empêcher cette exception d'être levée. Comme je l'ai dit, il devrait être possible de stocker un film sans stocker aucune information de genre/s.

Merci d'avance!

La méthode:

public List<MovieGenre> 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> movieGenre = new List<MovieGenre>(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();
        }
    }
}

Le sproc:

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 ('Error while trying to receive genre(s).',16,1)
    END CATCH
END
44
holyredbeard

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 nullables en utilisant le SqlDataReader.IsDBNull méthode:

http://msdn.Microsoft.com/en-us/library/system.data.sqlclient.sqldatareader.isdbnull.aspx

En supposant que GenreID et MovieGenreID sont des valeurs nulles, vous pouvez 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)
});
62
kaj

Modifiez votre instruction select comme suit pour gérer le problème nul.

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 --rest of your query...
7
Kaf

La réponse la plus simple consiste à remplacer les valeurs nulles par des valeurs non nulles. Essayer:

ALTER PROCEDURE usp_GetMovieGenreByMovieID
@MovieID int
AS
BEGIN
    BEGIN TRY
        SELECT m.MovieID, 
               coalesce(g.GenreID,0) GenreID, 
               coalesce(mg.MovieGenreID,0) MovieGenreID, 
               coalesce(g.Genre, 'Not Applicable') 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 ('Error while trying to receive genre(s).',16,1)
    END CATCH
END
2
user359040