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
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)
});
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...
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