Правильное соединение / реализация GroupJoin - PullRequest
3 голосов
/ 06 ноября 2010

Я пытался работать с методом Join и GroupJoin. Проблема кажется простой. Даны TableA и TableB в виде карт данных, таких что:

class MyDataContext : DataContext
{
    public Table<tblA> TableA;
    public Table<tblB> TableB;
}

... Я использую TableA в качестве основной таблицы и хочу объединиться в одно поле, CustomerID в TableB для получения [TableB].[LastName].

Не должно быть трудностей, за исключением того, что у меня возникают трудности с получением результатов для правильной работы. В TableA есть записи, которые мне нужны, независимо от совпадающего CustomerID в TableB. Походит на левое соединение - поэтому, читая здесь , я подражал тому, что предложил @tvanfosson:

// appropriately rewritten for my needs - so I thought...
private static IQueryable GetRecordsByView1(IQueryable<tblA> source)
{
    var records = source.GroupJoin(myContext.TableB,
                  info => info.CustomerID,
                  owner => owner.CustomerID,
                  (info, owner) => new
                  {
                      info.CustomerID,
                      Owner = owner.Select(o => o.LastName).DefaultIfEmpty(),
                      Store = info.Store,
                  })
                  .Select(record => new
                  {
                      record.CustomerID,
                      record.Owner,
                      record.Store,
                  });

    return records;
}

source является динамическим, так что один метод создает динамический запрос:

public static void QueryStores()
{
    IQueryable<tblA> source = myContext.TableA;

    if (criteriaA)
        source = source.Where(// something);

    if (criteriaB)
        source = source.Where(// something);

    // after processing criteria logic, determine type of view
    switch (byView)
    {
        case View1:
        {
            source = GetRecordsByView1(source);
            break;
        }

        //other case blocks
    }

    myGridView.DataSource = source;
}

Проблема: я получаю следующую ошибку:

Не удалось отформатировать узел 'OptionalValue' для выполнения в виде SQL.

Я полагаю, что это в следующей строке кода:

Owner = owner.Select(o => o.LastName).DefaultIfEmpty()

Что я здесь не так делаю? Я должен написать GroupJoin в качестве метода расширения.

Ответы [ 3 ]

3 голосов
/ 08 ноября 2010

Вы правы, что Owner = owner.Select(o => o.LastName).DefaultIfEmpty() - это линия, вызывающая ваши проблемы. Лучший обходной путь, который я нашел, - это что-то вроде этого:

var records = source.GroupJoin(myContext.TableB,
                  info => info.CustomerID,
                  owner => owner.CustomerID,
                  (info, owner) => new { info, owner }).ToList();
records.Select(x => new
                  {
                      x.info.CustomerID,
                      Owner = x.owner.First() == null ? new string[] {} : x.owner.Select(o => o.LastName).ToArray(),
                      Store = x.info.Store,
                  })
                  .Select(record => new
                  {
                      record.CustomerID,
                      record.Owner,
                      record.Store,
                  });

Это, конечно, не идеально (вы должны материализовать групповое объединение с помощью 'ToList'), и может быть лучшее решение, но это сработало для меня. Возможно, вам придется немного поиграть, чтобы заставить его работать как раз для вас, но я надеюсь, что это поможет вам на вашем пути.

2 голосов
/ 08 ноября 2010

Сначала ... @ Брайан заставил меня встать на правильный путь.Вот решение:

var records = source
              .GroupJoin(myContext.TableB,
              info => info.CustomerID,
              owner => owner.CustomerID,
              (info, owner) => new
              {
                  info,
                  Owner = owner.Select(o => o.LastName).First()
              })
              .Select(record => new
              {
                  record.info.CustomerID,
                  record.Owner,
                  record.info.Store
              });

Это дает мне точные желаемые результаты ...

0 голосов
/ 07 ноября 2010

Посмотрите на этот левый пример внешнего соединения: http://msdn.microsoft.com/en-us/library/bb397895.aspx

Соответствующий образец:

var query = from person in people
join pet in pets on person equals pet.Owner into gj
from subpet in gj.DefaultIfEmpty()
select new { person.FirstName, PetName = (subpet == null ? String.Empty : subpet.Name) }

Вы можете объединить результаты в gj, а затем использовать DefaultIfEmpty для создания ситуации внешнего соединения.и все равно получите нужные результаты.

Кто-то еще получил похожую ошибку, используя DefaultIfEmpty здесь: Макс или по умолчанию? http://blog.appelgren.org/2008/05/15/linq-to-sql-aggregates-and-empty-results/

HTH.

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