C# (ou Framework) n'aime pas ma requète SQL
J'ai cherché longtemps avant de comprendre ce qui coinçait car c'était une erreur d'exécution.
Voila le problème :
J'ai, dans SQL Server 2012, une vue qui fonctionne sans souci. Je décide de prendre juste la partie SELECT... et l'intégrer dans une appli Windows Form. J'ai déjà fait ce type d'appli avec un programme exemple du Coach Microsoft. Mais dans mon cas ça coince et l'erreur se ramasse sur le nom du champ.
D'abord voici ma requête SQL de ma vue SQL Server sans reproche
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
SELECT Auteurs.Nom, Auteurs.Prénom, Ouvrages.Titre,
Ouvrages.[Sous-titre], Catégories.[Nom de la catégorie],
Editeurs.Nom AS Editeur, Collections.[Titre de collection]
FROM Catégories INNER JOIN
Auteurs INNER JOIN
Editeurs INNER JOIN
Collections ON
Editeurs.éditeurID = Collections.éditeurID INNER JOIN
Ouvrages ON Editeurs.éditeurID = Ouvrages.éditeurID AND
Collections.collectionID = Ouvrages.collectionID ON
Auteurs.auteurID = Ouvrages.auteurID ON
Catégories.catégorieID = Ouvrages.catégorieID
GROUP BY Auteurs.Nom, Auteurs.Prénom, Ouvrages.Titre,
Ouvrages.[Sous-titre], Catégories.[Nom de la catégorie],
Editeurs.Nom, Collections.[Titre de collection] |
Collée dans une variable string (en supprimant les retours à la ligne que C# n'aime pas, même si ça fait un code moche comme tout) ça ne fonctionne pas et ExecuteReader se ramasse avec ce qu'il considère comme un dépassement de capacité sur le premier champ rencontré. Erreur pas évidente et j'ai séché longtemps. Mettre des crochets [Auteurs].[Nom] de résout rien. En fait c'est le nom de la table (Auteurs) qui précède qui ne va pas. Simplifiant ma requête à l'extrême aux fins de débogage ça ne fonctionnait pas mieux avec
Code:
SELECT Auteurs.Prénom, Auteurs.Nom FROM Auteurs
et parfaitement avec
Code:
SELECT Prénom, Nom FROM Auteurs
Pourquoi donc ne pas pouvoir préfixer le nom du champ avec le nom de la table comme c'est une bonne habitude prise en SQL ? D'autant plus conseillé que lors d'un SELECT à rallonge avec des JOIN en pagaille le moteur SQL risque de grimacer sur des ambigüités.
Question subsidiaire : Peut-on utiliser directement une vue dans un code Windows Form de la même façon qu'on utilise une procédure stockée (en l'appelant par son nom) ?
Merci à tous de vous pencher sur mes petites misères.
C'est résolu, mais j'ai dis des sottises précédemment
En fait ce n'est nullement la requête SQL qui pose problème. Si elle est correcte pour Transact-SQL on peut se demander pourquoi Visual Studio via Framework 4 la refuserait. Donc préfixer les champs par les noms des tables est tout à fait correct. Par contre il est interdit, sous peine d'erreur d'exécution, d'y mettre une clause GROUP BY. ORDER BY est accepté mais ne produit aucun effet.
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13
| string strRequete =
"SELECT Auteurs.Nom, Auteurs.Prénom, Ouvrages.Titre, " +
"Ouvrages.[Sous-titre], Catégories.[Nom de la catégorie], " +
"Editeurs.Nom AS Editeur, Collections.[Titre de collection] " +
"FROM Catégories INNER JOIN " +
"Auteurs INNER JOIN " +
"Editeurs INNER JOIN " +
"Collections ON " +
"Editeurs.éditeurID = Collections.éditeurID INNER JOIN " +
"Ouvrages ON Editeurs.éditeurID = Ouvrages.éditeurID AND " +
"Collections.collectionID = Ouvrages.collectionID ON " +
"Auteurs.auteurID = Ouvrages.auteurID ON " +
"Catégories.catégorieID = Ouvrages.catégorieID "; |
C'est dans l'utilisation de la fonction Executereader() qu'on ne peut se permettre de préfixer le champ par le nom de la table, c'est interdit.
Mais alors comment lever les ambigüité des noms de champs ? Car avec des champs "noms" et "prénoms" il peut y en avoir légion avec des tables de "représentants", "clients", "auteurs", "fournisseurs", etc.
C'est là où les alias sont utiles, mais ils doivent être mis dans la requête SQL et uniquement dans elle. Dans le cas ci-dessus "Nom" est présent à la fois dans la table Editeurs et Auteurs. En faisant un alias "Editeur" pour Editeurs.Nom l'ambigüité est levée et le code ci-dessous fonctionne sans problème
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| var result = new DC.Ouvrages_par_auteur();
using (var cn = new SqlConnection(BibliWM.DA.Properties.Settings.Default.BibliWMConnectionString))
{
cn.Open();
var cd = new SqlCommand(strRequete, cn);
using (var dr = cd.ExecuteReader())
{
while (dr.Read())
{
result.Add
(
new DC.Ouvrage_par_auteur()
{
strNom = dr["Nom"] != DBNull.Value ? (string)dr["Nom"] : string.Empty,
strPrénom = dr["Prénom"] != DBNull.Value ? (string)dr["Prénom"] : string.Empty,
strTitre = dr["Titre"] != DBNull.Value ? (string)dr["Titre"] : string.Empty,
strSousTitre = dr["Sous-titre"] != DBNull.Value ? (string)dr["Sous-titre"] : string.Empty,
strNomCatégorie = dr["Nom de la catégorie"] != DBNull.Value ? (string)dr["Nom de la catégorie"] : string.Empty,
strEditeur = dr["Editeur"] != DBNull.Value ? (string)dr["Editeur"] : string.Empty,
strCollection = dr["Titre de collection"] != DBNull.Value ? (string)dr["Titre de collection"] : string.Empty,
}
);
}
}
}
return result; |
Donc si ma rectification d'erreur de débutant en Windows Forms peut éviter à d'autres débutants d'y tomber...