2010-12-04 4 views
1

У меня есть 3 таблицы, которые мне нужно использовать:
бренд-
BrandID
Имя
помощь при запросе Linq в три таблицы

BrandSource-
BrandID
SourceId

Source-
SourceID
SourceName

Таким образом, у меня много-много отношений с BrandSource, являющимся моей промежуточной таблицей. У меня есть столбец Brand, который отображается в таблице, и я создал новый столбец для исходного изображения. По сути, если есть 5 источников для одного бренда, мне нужно, чтобы он показывал одну строку для бренда и 5 различных исходных изображений в новом столбце, который я сделал (5 изображений в одной ячейке).

Поскольку я присоединился к трем таблицам, очевидно, что в таблице BrandSource имеется 5 строк и отображает 5 строк каждой марки с единственным исходным изображением в ячейке.

Я уверен, что я мог бы выбрать различные бренды, но это все еще не решает мою проблему, как я могу получить все исходные изображения для каждой марки, чтобы они отображались в одной и той же ячейке.

Вот мой код linq: (Как вы можете видеть, здесь есть некоторая информация, которую я недавно оставил для краткости).

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

А вот как я использую его:

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>"; 

    } 

ответ

3

У вас хорошее начало, но я думаю, вам будет лучше не выполнять тройное соединение. Linq-to-sql может обрабатывать детали этого для вас. Если вы отступите от аспекта запроса на секунду и начнете с желаемого результата, вы сделаете лучше. Из того, что я могу сказать, тип объекта, который вы хотите из этого, представляет собой список брендов, и каждый бренд должен содержать список его источников. Вот как вы это делаете (начиная с загрузкой 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 показывает, что это выполняется в одном запросе, но внутренности сборки вашего List<Source> в вашем объекте результата происходит за кулисами. Вот что выполняет LINQPad:

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] 

А вот некоторые тестовые данные для тех, кто следует по дома:

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 

Обратите внимание, что вы получите пустой список источников для бренда # 3 этот путь, что и Думаю, ты хочешь. Ваш оригинальный запрос INNER JOIN ed Brand № 3.

Наконец, вот пример того, как вы будете использовать свой результат запроса:

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

Это именно то, что я искал. Спасибо. – 2010-12-04 22:44:50

0

Сортировка запроса LINQ по BrandID затем использовать переменную, чтобы следить, если это новый бренд.

int lastBrandID = 0; 
string closeHtml = ""; 
foreach (var result in join) 
    { 
     if(result.Brand.BrandID != lastBrandID) 
     { 
      resultSpan.InnerHtml += closeHtml; 
      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>"; 
      closeHtml = "</td><td>" + result.Brand.DateCreated + "</td><td>" + result.Brand.DateModified + "</td></tr>"; 
      lastBrandID = result.Brand.BrandID; 
     } 
     resultSpan.InnerHtml += "<img src='"+result.source+"'></img>"; 
    } 
    resultSpan.InnerHtml += closeHtml; 

На боковой ноте используйте StringBuilder вместо конкатенирования строк. http://msdn.microsoft.com/en-us/library/2839d5h5%28v=VS.100%29.aspx

0

Вы можете использовать GroupBy для этого (или group .. by .. into в запросе) на исходном запросе таким образом:

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

Это работает, только если у вас есть EntitySets/Refs. Это может быть хорошим выбором в этом случае, так как отношения являются классическими pk-> fk. – mattmc3 2010-12-04 23:40:12