Linq to sql - pb requête avec jointures

Résolu
leati24 Messages postés 9 Date d'inscription samedi 2 juin 2007 Statut Membre Dernière intervention 27 juillet 2009 - 8 juin 2009 à 17:30
leati24 Messages postés 9 Date d'inscription samedi 2 juin 2007 Statut Membre Dernière intervention 27 juillet 2009 - 11 juin 2009 à 15:55
Bonjour,

Je développe une application en asp.net c#. J'utilise SQL Server pour stocker ma base de données et linq to sql pour accéder aux données.

Concrètement, j'ai trois tables : Personne (idPersonne, nomPersonne), Poste(idPoste, libPoste) et Travailler(idPersonne, idPoste). Je souhaiterais comme résultats les champs nomPersonne et libPoste. Pour ca j'utilise la requête suivante :

string reqSelect = "SELECT Personne.nomPersonne, Poste.libPoste FROM Personne
INNER JOIN Travailler ON Personne.idPersonne = Travailler.idPersonne
INNER JOIN Poste ON Travailler.idPoste = Poste.idPoste";

Et ensuite je l'exécute avec la méthode ExecuteQuery. Cependant, je ne sais pas quel type de retour indiqué puisque nomPersonne et libPoste ne forment pas un objet et ne sont pas dans la même table en base de données.

Auriez-vous des suggestions ?
Merci
A voir également:

12 réponses

krimog Messages postés 1860 Date d'inscription lundi 28 novembre 2005 Statut Membre Dernière intervention 14 février 2015 49
9 juin 2009 à 11:59
Dans mon exemple, q a un type de retour, qui est ce qu'on appelle un type anonyme.

La solution la plus simple est de ne pas faire de cast : requete.ToList();
Cependant, si tu souhaites réutiliser les objets après, tu peux également faire une classe perso du genre
class MonEnsemble
{
    public LeTypeDeMaSource1 maSource1 {get; set;}
    public LeTypeDeMaSource2 maSource2 {get; set;}
    public LeTypeDeMaSource3 maSource3 {get; set;}
    public MonEnsemble(LeTypeDeMaSource1 source1, LeTypeDeMaSource2 source2, LeTypeDeMaSource3 source3)
    {
        maSource1 = source1;
        maSource2 = source2;
        maSource3 = source3;
    }
}

Et dans ta requête linq : IEnumerable<MonEnsemble> q = from ... in ... where ... select new MonEnsemble(a,b,c);

Krimog : while (!(succeed = try())) ;
- NON, "LE BAR" n'est PAS un langage de programmation ! -
3
krimog Messages postés 1860 Date d'inscription lundi 28 novembre 2005 Statut Membre Dernière intervention 14 février 2015 49
8 juin 2009 à 18:21
Salut

Pourquoi utilises-tu une requête SQL si tu utilises Linq to SQL ???

            var q = from a in maSource1
                    from b in maSource2
                    from c in maSource3
                    where a.Id == b.Id
                    && a.Id == c.Id
                    select new
                    {
                        // C'est à ça que ressemblera ta sortie
                        Id = a.Id,
                        Machin = b.Machin,
                        Truc = c.Truc
                    };
            foreach (var element in q)
            {
                Console.WriteLine(element.Machin);
            }

Krimog : while (!(succeed = try())) ;
- NON, "LE BAR" n'est PAS un langage de programmation ! -
0
leati24 Messages postés 9 Date d'inscription samedi 2 juin 2007 Statut Membre Dernière intervention 27 juillet 2009
8 juin 2009 à 20:25
Je ne peux pas réellement utiliser de requête sous cette forme parce que j'ai des dizaines de paramètres dans ma fonction et je dois les inclure dans ma requête que s'ils ne sont pas égaux à "null"...
0
krimog Messages postés 1860 Date d'inscription lundi 28 novembre 2005 Statut Membre Dernière intervention 14 février 2015 49
9 juin 2009 à 09:52
Où est le problème ?

where a.Id == b.Id
&& a.Id == c.Id&& (machin null || machin valeur)&& (bidule null || bidule.Propriete autreValeur)

Krimog : while (!(succeed = try())) ;
- NON, "LE BAR" n'est PAS un langage de programmation ! -
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
leati24 Messages postés 9 Date d'inscription samedi 2 juin 2007 Statut Membre Dernière intervention 27 juillet 2009
9 juin 2009 à 10:09
Le problème est que si mon paramètre est nul je ne veux pas le prendre en compte dans ma requête de sélection... Donc ma clause where vaudra dans le premier cas :

where a.Id = b.Id
&& a.Id = c.Id
&& parametre == valeur

et dans le deuxième cas :

where a.Id = b.Id

&& a.Id = c.Id

Et j'ai une dizaine de paramètres! Donc j'utilise une requête sql que je stocke dans un string et si mon paramètre n'est pas égal à null je l'ajoute dans la requête.
0
krimog Messages postés 1860 Date d'inscription lundi 28 novembre 2005 Statut Membre Dernière intervention 14 février 2015 49
9 juin 2009 à 10:32
0
krimog Messages postés 1860 Date d'inscription lundi 28 novembre 2005 Statut Membre Dernière intervention 14 février 2015 49
9 juin 2009 à 10:45
0) Désolé, problème de post...
1) N'oublie pas de doubler les = dans les conditions des requêtes Linq
2) J'ai parfaitement compris ton problème, tu ne sembles pas avoir compris ma solution

effectivement, faire
if (parametre != null)
{
...where a.Id == b.Id
&& a.Id == c.Id
&& parametre == valeur...
}else{
...where a.Id == b.Id
&& a.Id == c.Id...
}
avec une dizaine de paramètres, ça peut paraître long. Cependant, le code suivant fait EXACTEMENT la même chose :
...where a.Id == b.Id
&& a.Id == c.Id&& (parametre null || parametre valeur)...

En C#, les conditions sont traitées de gauche à droite. Il sort de la condition dès qu'il a assez d'éléments pour connaître la réponse (dans le cas d'un ||, il sort tout de suite si la première partie est vraie, ou passe à la deuxième sinon).
Donc si "parametre" est null, il passera directement à la suite. Sinon, il vérifiera si "parametre" est égal à "valeur".

Ce qui fait qu'avec 10 paramètres, on arrive à qqche du genre :

...where a.Id == b.Id
&& a.Id == c.Id

&& (param0 null || param0 valeur0)

&& (param1 null || param1 valeur1)

&& (param2 null || param2 valeur2)

&& (param3 null || param3 valeur3)

&& (param4 null || param4 valeur4)

&& (param5 null || param5 valeur5)

&& (param6 null || param6 valeur6)

&& (param7 null || param7 valeur7)

&& (param8 null || param8 valeur8)

&& (param9 null || param9 valeur9)...

Personnellement, ça ne me semble pas trop compliqué. Linq a été fait pour pas qu'on ait à utiliser du SQL, autant en profiter !
PS : si un paramêtre est d'un type non nullable, passé en nullable (int?, bool?, char?, double?...) tu devras remplacer paramX valeurX par paramX.value valeurX.

Krimog : while (!(succeed = try())) ;
- NON, "LE BAR" n'est PAS un langage de programmation ! -
0
leati24 Messages postés 9 Date d'inscription samedi 2 juin 2007 Statut Membre Dernière intervention 27 juillet 2009
9 juin 2009 à 11:32
Effectivement, je n'avais pas compris ta solution. Merci pour cette solution, je vais pouvoir ré-utiliser linq. Cependant, ca ne règle pas (tout à fait) mon problème initial.

Quand tu fais :
var q = from a in maSource1
                    from b in maSource2
                    from c in maSource3
                    where a.Id == b.Id
                    && a.Id == c.Id
                    select new
                    {
                        // C'est à ça que ressemblera ta sortie
                        Id = a.Id,
                        Machin = b.Machin,
                        Truc = c.Truc
                    };

la variable q n'a pas de type de retour puisque Id, machin et truc proviennent de trois tables différentes.
Je souhaite récupèrer cette sortie pour la mettre dans un gridView. Et donc la transformer en list (avec ToList<>()) pour pouvoir utiliser la pagination dans mon gridView (IEnumerable et IQueryable ne permet pas d'utiliser la pagination dans un gridView). Si je fais : return (q.ToList<?>()); par quoi je remplace le "?" dans ma fonction ?

J'ai trouvé une solution qui est d'écrire : (((IQueryable)requete).Cast<Object>().ToList<Object>()); Tu penses que c'est la meilleure solution ?

Merci de ton aide et désolée d'avoir un peu le cerveau lent
0
leati24 Messages postés 9 Date d'inscription samedi 2 juin 2007 Statut Membre Dernière intervention 27 juillet 2009
9 juin 2009 à 13:52
Si je mets pas le Cast<Object>(), j'ai une erreur de compilation : "Impossible de convertir implicitement le type 'System.Collections.Generic.List' en 'System.Web.UI.MobileControls.List'"

C'est effectivement la solution que j'avais trouvé (de créer une classe perso) mais je me demandais s'il n'y avait pas plus simple.

Merci beaucoup de ton aide très utile ;)
0
nhervagault Messages postés 6063 Date d'inscription dimanche 13 avril 2003 Statut Membre Dernière intervention 15 juillet 2011 37
9 juin 2009 à 15:39
Salut,

Te permettra de supprimer le type anonyme

select new
MobileControls
                    {
Id =
a.Id,.....}

                    

Sinon tu peux empiler les requetes linq

var q = from c in source
....

var q2 = from d in q
            where ......

q2.ToList()

Mettre le toList au dernier moment pour que la requete SQL soit faite à ce moment.
Si non tu risques de raméné trop d'enregistement et les restriction des where se feront en linq2objet (ie en mémoire)

Bon dev
0
leati24 Messages postés 9 Date d'inscription samedi 2 juin 2007 Statut Membre Dernière intervention 27 juillet 2009
11 juin 2009 à 15:48
Merci nhervagault pour ta réponse, je vais également tester ca.

Krimog, je reviens vers toi parce que finalement ton exemple :
where a.Id == b.Id
&& a.Id == c.Id&& (machin null || machin valeur)&& (bidule null || bidule.Propriete autreValeur)

ne fonctionne pas. Je vais essayer d'être plus claire parce qu'en me relisant je trouve que je donne trop peu d'informations.

Sur ma page aspx, j'ai deux champs : champ1 et champ2 ainsi qu'un bouton rechercher. Lorsque l'utilisateur clique sur le bouton rechercher, champ1 et champ2 peuvent être vide. C'est dans ce cas que je souhaite ne pas les prendre en compte dans ma requête. C'est à dire, si champ1 et champ2 sont nuls :
where maTable1.id == maTable2.id

Si champ1 vaut "toto" et champ2 est toujours à vide par exemple, j'aurais la requête suivante :
where maTable1.id == maTable2.id
&& maTable1.champ = champ1
Ce qui veut dire que champ2 peut valoir toutes les valeurs qu'il souhaite : 'a', 'ahjkla', null, '+=)az'...

Toi tu m'aurais proposé d'écrire :
where maTable1.id == maTable2.id&& (maTable1.champ null || maTable1.champ ) ce qui me ramènerait seulement les enregistrements où maTable1.champ null.

J'espère avoir compris ce que tu me proposais. En tout cas, en testant dans mon code ca ne me retourne aucun enregistrement parce que aucun de mes champs sont null...
0
leati24 Messages postés 9 Date d'inscription samedi 2 juin 2007 Statut Membre Dernière intervention 27 juillet 2009
11 juin 2009 à 15:55
Je supprime mon dernier message. Tout fonctionne. Je n'exécute pas la bonne version :S
0
Rejoignez-nous