web-dev-qa-db-fra.com

LINQ to SQL: plusieurs jointures sur plusieurs colonnes. Est-ce possible?

Donné:

Une table nommée TABLE_1 avec les colonnes suivantes:

  • ID
  • ColumnA
  • ColumnB
  • ColumnC

J'ai une requête SQL où TABLE_1 rejoint sur lui-même deux fois basé sur ColumnA, ColumnB, ColumnC. La requête pourrait ressembler à ceci:

Select t1.ID, t2.ID, t3.ID
  From TABLE_1 t1
  Left Join TABLE_1 t2 On
       t1.ColumnA = t2.ColumnA
   And t1.ColumnB = t2.ColumnB
   And t1.ColumnC = t2.ColumnC
  Left Join TABLE_1 t3 On
       t2.ColumnA = t3.ColumnA
   And t2.ColumnB = t3.ColumnB
   And t2.ColumnC = t3.ColumnC
... and query continues on etc.

Problème:

J'ai besoin que cette requête soit réécrite dans LINQ. J'ai essayé de tenter ma chance:

var query =
    from t1 in myTABLE1List // List<TABLE_1>
    join t2 in myTABLE1List
      on t1.ColumnA equals t2.ColumnA
      && t1.ColumnB equals t2.ColumnA
    // ... and at this point intellisense is making it very obvious
    // I am doing something wrong :(

Comment écrire ma requête dans LINQ? Qu'est-ce que je fais mal?

112
DJTripleThreat

La jonction sur plusieurs colonnes dans Linq to SQL est un peu différente.

var query =
    from t1 in myTABLE1List // List<TABLE_1>
    join t2 in myTABLE1List
      on new { t1.ColumnA, t1.ColumnB } equals new { t2.ColumnA, t2.ColumnB }
    ...

Vous devez tirer parti des types anonymes et composer un type pour les multiples colonnes avec lesquelles vous souhaitez comparer.

Cela semble déroutant au début, mais une fois que vous aurez compris la façon dont le code SQL est composé à partir des expressions, cela aura plus de sens, sous les couvertures, cela générera le type de jointure que vous recherchez.

EDITAjout d'un exemple pour la deuxième jointure basée sur un commentaire.

var query =
    from t1 in myTABLE1List // List<TABLE_1>
    join t2 in myTABLE1List
      on new { A = t1.ColumnA, B = t1.ColumnB } equals new { A = t2.ColumnA, B = t2.ColumnB }
    join t3 in myTABLE1List
      on new { A = t2.ColumnA, B =  t2.ColumnB } equals new { A = t3.ColumnA, B = t3.ColumnB }
    ...
206
Quintin Robinson

Title_Authors est une recherche de deux choses joignent à la fois les résultats du projet et continuent à chaîner

        DataClasses1DataContext db = new DataClasses1DataContext();
        var queryresults = from a in db.Authors                                          
                    join ba in db.Title_Authors                           
                    on a.Au_ID equals ba.Au_ID into idAuthor
                    from c in idAuthor
                    join t in db.Titles  
                    on c.ISBN equals t.ISBN 
                    select new { Author = a.Author1,Title= t.Title1 };

        foreach (var item in queryresults)
        {
            MessageBox.Show(item.Author);
            MessageBox.Show(item.Title);
            return;
        }
9
BionicCyborg

Dans LINQ2SQL, vous devez rarement explicitement vous joindre lorsque vous utilisez des jointures internes.

Si vous avez des relations de clé étrangère appropriées dans votre base de données, vous obtiendrez automatiquement une relation dans le concepteur LINQ (sinon, vous pouvez créer une relation manuellement dans le concepteur, même si vous devez vraiment avoir des relations appropriées dans votre base de données).

parent-child relation

Ensuite, vous pouvez simplement accéder aux tables associées avec la "notation par points"

var q = from child in context.Childs
        where child.Parent.col2 == 4
        select new
        {
            childCol1 = child.col1,
            parentCol1 = child.Parent.col1,
        };

va générer la requête

SELECT [t0].[col1] AS [childCol1], [t1].[col1] AS [parentCol1]
FROM [dbo].[Child] AS [t0]
INNER JOIN [dbo].[Parent] AS [t1] ON ([t1].[col1] = [t0].[col1]) AND ([t1].[col2] = [t0].[col2])
WHERE [t1].[col2] = @p0
-- @p0: Input Int (Size = -1; Prec = 0; Scale = 0) [4]
-- Context: SqlProvider(Sql2008) Model: AttributedMetaModel Build: 4.0.30319.1

À mon avis, cela est beaucoup plus lisible et vous permet de vous concentrer sur vos conditions spéciales et non sur les mécanismes réels de la jointure.

Modifier
Ceci n’est bien sûr applicable que lorsque vous souhaitez rejoindre le modèle de base de données. Si vous souhaitez rejoindre "en dehors du modèle", vous devez recourir aux jointures manuelles, comme indiqué dans le answer from Quintin Robinson

9
Albin Sunnanbo

U peut également utiliser:

var query =
    from t1 in myTABLE1List 
    join t2 in myTABLE1List
      on new { ColA=t1.ColumnA, ColB=t1.ColumnB } equals new { ColA=t2.ColumnA, ColB=t2.ColumnB }
    join t3 in myTABLE1List
      on new {ColC=t2.ColumnA, ColD=t2.ColumnB } equals new { ColC=t3.ColumnA, ColD=t3.ColumnB }
8
Baqer Naqvi

Je voudrais donner un autre exemple dans lequel des jointures multiples (3) sont utilisées.

 DataClasses1DataContext ctx = new DataClasses1DataContext();

        var Owners = ctx.OwnerMasters;
        var Category = ctx.CategoryMasters;
        var Status = ctx.StatusMasters;
        var Tasks = ctx.TaskMasters;

        var xyz = from t in Tasks
                  join c in Category
                  on t.TaskCategory equals c.CategoryID
                  join s in Status
                  on t.TaskStatus equals s.StatusID
                  join o in Owners
                  on t.TaskOwner equals o.OwnerID
                  select new
                  {
                      t.TaskID,
                      t.TaskShortDescription,
                      c.CategoryName,
                      s.StatusName,
                      o.OwnerName
                  };
3
user3477428

Vous pouvez également participer si le nombre de colonnes n'est pas identique dans les deux tables et mapper une valeur statique sur une colonne de table.

from t1 in Table1 
join t2 in Table2 
on new {X = t1.Column1, Y = 0 } on new {X = t2.Column1, Y = t2.Column2 }
select new {t1, t2}
0
Ankit Arya