2010-12-04 11 views
1

J'ai 3 tables que je dois utiliser:
Brand-
BrandID
Nom
aide avec un LINQ trois tables requête

BrandSource-
BrandID
SourceID

Source-
SourceID
SourceName
Image

Donc, j'ai une relation de many-many avec BrandSource étant ma table intermédiaire. J'ai chaque colonne de marque affichée dans une table et j'ai fait une nouvelle colonne pour l'image source. Essentiellement, s'il y a 5 sources pour une marque, j'en ai besoin pour montrer une rangée pour la marque et les 5 images sources différentes dans la nouvelle colonne que j'ai faite (5 images dans une cellule). Depuis que j'ai joint les trois tables, il est évident qu'il y a 5 lignes dans la table BrandSource et affiche 5 lignes de chaque marque avec une seule image source dans une cellule. Je suis sûr que je pourrais sélectionner des marques distinctes, mais cela ne résout toujours pas mon problème de comment je peux obtenir toutes les images de la source pour chaque marque à apparaître dans la même cellule.

Voici mon code linq: (Comme vous pouvez le voir il ya quelques informations ici que j'ai omis ci-dessus pour la brièveté).

var join = from b in db.Brands 
       join bs in db.Brands_Sources on b.BrandID equals bs.BrandID 
       join sb in db.Sources on bs.SourceID equals sb.SourceID 
       select new { Brand = b, source = sb.Image, c = b.Description.Length < 204 ? b.Description : b.Description.Substring(0, 204) + "..." }; 

Et voici comment je l'utilise:

foreach (var result in join) 
    { 
     bool a = result.Brand.Active; 
     string chk = string.Empty; 
     if (a == true) 
      chk = "checked='checked'"; 
     else 
      chk = ""; 

      resultSpan.InnerHtml += "<tr><td><input type='checkbox' " + chk + "></td><td width='1%'><img width='50px' src='" + result.Brand.Image + "'</img></td>" + 
       "<td>" + result.Brand.Name + "</td><td width='60%'>" + result.c + "</td><td><img src='"+result.source+"'></img></td><td>" + result.Brand.DateCreated + "</td><td>" + result.Brand.DateModified + "</td></tr>"; 

    } 

Répondre

3

Vous avez un bon début, mais je pense que vous seriez mieux servi ne pas faire le triple rejoindre vous-même. Linq-to-sql peut gérer les détails de cela pour vous. Si vous vous éloignez de l'aspect de la requête pendant une seconde et commencez avec le résultat souhaité, vous ferez mieux. De ce que je peux dire, le type d'objet que vous voulez en sortir est une liste de marques, et chaque marque devrait contenir une liste de ses sources. Voilà comment vous le faites (en commençant par le téléchargement LinqPad) ...

// LinqPad C# statement(s) 
var results = 
from b in Brands 
select new { 
    Brand = b, 
    Sources = (
     from s in Sources 
     join xref in BrandSources on s.SourceID equals xref.SourceID 
     where xref.BrandID == b.BrandID 
     select s 
    ).ToList() 
}; 

result.Dump(); // show result in LinqPad 

LINQPad montre que cette exécute en une seule requête, mais le courage de monter vos List<Source> dans votre objet résultat se produit dans les coulisses. Voici ce que LINQPad exécute:

SELECT [t0].[BrandID], [t0].[Name], [t1].[SourceID], [t1].[SourceName], [t1].[Image], (
    SELECT COUNT(*) 
    FROM [Source] AS [t3] 
    INNER JOIN [BrandSource] AS [t4] ON [t3].[SourceID] = [t4].[SourceID] 
    WHERE [t4].[BrandID] = [t0].[BrandID] 
    ) AS [value] 
FROM [Brand] AS [t0] 
LEFT OUTER JOIN ([Source] AS [t1] 
    INNER JOIN [BrandSource] AS [t2] ON [t1].[SourceID] = [t2].[SourceID]) ON [t2].[BrandID] = [t0].[BrandID] 

Et voici quelques données de test pour ceux qui suivent à la maison:

create table Brand (
BrandID int, 
Name varchar(50), 
) 

create table BrandSource (
BrandID int, 
SourceID int 
) 

create table Source (
SourceID int, 
SourceName varchar(50), 
[Image] varchar(50) 
) 

insert into Brand select 1, 'Brand1' 
insert into Brand select 2, 'Brand2' 
insert into Brand select 3, 'Brand3' 

insert into Source select 1, 'Source1', 'src1.gif' 
insert into Source select 2, 'Source2', 'src2.jpg' 
insert into Source select 3, 'Source3', 'src3.bmp' 
insert into Source select 4, 'Source4', 'src4.png' 
insert into Source select 5, 'Source5', 'src5.raw' 

insert into BrandSource select 1, 1 
insert into BrandSource select 1, 2 
insert into BrandSource select 1, 3 
insert into BrandSource select 2, 2 
insert into BrandSource select 2, 4 

select * from Brand 
select * from BrandSource 
select * from Source 

Notez que vous obtenez une liste vide de sources pour la marque n ° 3 de cette façon, ce qui est Je suppose que tu voudrais. Votre requête originale INNER JOIN ed Marque # 3 de suite.

Enfin, voici un exemple de la façon dont vous souhaitez utiliser votre résultat de la requête:

foreach (var result in results) { 
    string chk = (result.Brand.Active ? " checked='checked'" : ""); 
    var buf = new StringBuilder(); 
    buf.Append("<tr>"); 
    buf.AppendFormat("<td><input type='checkbox'{0}></td>", chk); 
    buf.AppendFormat("<td width='1%'><img width='50px' src='{0}'></img></td>", result.Brand.Image); 
    buf.AppendFormat("<td>{0}</td>", result.Brand.Name); 
    buf.Append("<td>"); 

    foreach(var src in result.Sources) { 
     buf.AppendFormat("<img src='{0}'></img>", src.Image); 
    } 

    buf.Append("</td>"); 
    buf.Append("</tr>"); 

    resultSpan.InnerHtml = buf.ToString(); 

} 
+0

c'est exactement ce que je cherchais. Je vous remercie. –

0

Vous pouvez utiliser GroupBy pour cela (ou group .. by .. into dans une requête) sur votre requête initiale ainsi:

var groups = join.GroupBy(b => b.Brand); 

foreach (var group in groups) 
{ 
    var brand = group.Key; 
    foreach (var row in group) 
    { 
     // you get the idea 
    } 

} 
-1
DataLoadOptions myOptions = new DataLoadOptions(); 
myOptions.LoadWith<Brand>(b => b.Brand_Sources); 
myOptions.LoadWith<Brand_Source>(bs => bs.Source); 

myDataContext.LoadOptions = myOptions; 


    // normally, some filtering is done, 
    // instead of reading the entire table. 
foreach(Brand brand in myDataContext.Brands) 
{ 
    List<Source> Sources = brand.Brand_Sources.Select(bs => bs.Source).ToList(); 

    // do stuff with brand and Sources 
} 
+0

Cela fonctionne uniquement si vous avez configuré EntitySets/Refs. Cela pourrait être un bon choix dans ce cas puisque les relations sont classiques pk-> fk. – mattmc3