помочь с запросом linq из трех таблиц - PullRequest
1 голос
/ 04 декабря 2010

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

BrandSource-BrandIDSourceId

Источник-SourceIdSourceNameОбраз

Так что у меня много-много отношений с BrandSource, являющимся моей промежуточной таблицей.Каждый столбец «Марка» отображается в таблице, и я создал новый столбец для исходного изображения.По сути, если есть 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>";

    }

Ответы [ 4 ]

3 голосов
/ 04 декабря 2010

У тебя хорошее начало, но я думаю, что тебе лучше обслужить, если ты не сделаешь тройное соединение. 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 Марка # 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 голосов
/ 05 декабря 2010
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 голосов
/ 04 декабря 2010

Вы можете использовать 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
    }

}
0 голосов
/ 04 декабря 2010

Сортировка запроса 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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...