LINQ to XML + левое объединение + группировка по = сбой - PullRequest
1 голос
/ 16 июля 2009

У меня есть две таблицы:

block: int id, [other columns...]
blockInstance: int id, int blockId (references Block.Id), [other columns...]

Моя цель состоит в том, чтобы сгенерировать перечисление объектов блока с двумя свойствами: (1) Id (идентификатор блока) и (2) InstanceCount (количество экземпляров для блока). В настоящее время мой XML-файл не содержит блочных экземпляров (эта таблица существует, но содержит ноль строк).

Вот мой (нерабочий) запрос:

var groupedBlocks =
    from
        b in _tableDictionary["block"].Elements()
    join
        bi in _tableDictionary["blockInstance"].Elements()
        on b.Element(_ns + "id").Value equals bi.Element(_ns + "blockId").Value into j
    from
        lj in j.DefaultIfEmpty()
    group
        lj by b.Element(_ns + "id").Value into g
    select new
    {
        Id = g.Key,
        InstanceCount = g.Count(i => i.Element(_ns + "blockId") != null)
    };

Проблема связана с предикатом (лямбда-выражением) для g.Count (). Если я удаляю предикат и просто использую g.Count (), запрос генерирует правильное количество строк, но InstanceCount для каждой строки равен 1, что неверно (он должен быть равен нулю). При наличии предиката запрос возвращает ноль строк, и, если я пытаюсь просмотреть ResultsView в отладчике, он говорит: «Исключение: ссылка на объект не установлена ​​на экземпляр объекта».

Мое величайшее замешательство заключается в том, что именно является"i" в моем лямбда-выражении. Я знаю, что это XElement, но что этот XElement содержит, когда данные являются результатом объединения (в данном случае, левого внешнего соединения)?

Хорошо, у меня появилась еще одна идея, когда я печатал это, и это действительно сработало :-), но я понятия не имею, почему :-(, поэтому я все еще собираюсь задать вопрос ;-).

Если я изменю код ошибки на ...

InstanceCount = g.Count(i => i != null)

... это работает. Но почему?! Опять же, что передается в выражении ламба? И почему это ноль?

Спасибо!

Ответы [ 2 ]

2 голосов
/ 16 июля 2009

i , как указано в числе групп, эквивалентно lj , которое возвращается из перечисления j.DefaultIfEmpty () .

DefaultIfEmpty () в этом контексте вернет значение по умолчанию для типа элемента, где элемент не имеет выходного совпадения с предыдущим оператором join..into,

В случае ссылочных типов ( XElement является ссылочным типом) значение по умолчанию всегда равно null, поэтому вы получаете исключение null для ссылки и почему проверка на null сначала устраняет проблему .

РЕДАКТИРОВАТЬ:

Альтернативный метод, позволяющий избежать группировки с помощью подзапроса:

var groupedBlocks = 
    from b in _tableDictionary["block"].Elements() 
    select new 
    { 
        Id = b.Element(_ns + "id").Value, 
        InstanceCount = (from bi in _tableDictionary["blockInstance"].Elements() 
                         where bi.Element(_ns + "blockId").Value == 
                               b.Element(_ns + "id").Value
                         select bi).Count()
    };
0 голосов
/ 16 июля 2009

Параметр, передаваемый в счетную лямбду, относится к тому типу, который вы группируете. Это потому, что вы вызываете Count в контексте g, который является IGrouping<string, XElement>.

Итак, i - это XElement.

В вашем первом запросе вы фактически проверяли первого потомка сгруппированного XElement (обращаясь к методу i.Element), поэтому он не сработал.

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