Хобрук: Ваш путь к мастерству в программировании

LinqToEntities использует меньше (‹) в пределах LEFT OUTER JOIN

Я работаю с коллегой, и мы пытаемся воспроизвести следующий SQL-запрос, используя LinqToEntities (Entity Framework v4.0)

SELECT t1.*
FROM [dbo].LocaleStringResource AS t1
  LEFT OUTER JOIN [dbo].LocaleStringResource AS t2
    ON (t1.ResourceName = t2.ResourceName AND t1.AccountId < t2.AccountId)
WHERE t2.ResourceName IS NULL;

По сути, это говорит о том, что возвращайте нам только самые высокие идентификаторы AccountId, где есть более одного соответствующего ResourceName. У нас это пока...

localeStringResource = from e1 in localeStringResource
  join e2 in localeStringResource
  on new { e1.ResourceName, e1.AccountId } equals new { e2.ResourceName, e2.AccountId }
  where e2.ResourceName == null
  select e1;

Но мы, похоже, не можем решить, как добиться эквивалента меньшего, чем (‹) в ЛЕВОМ ВНЕШНЕМ СОЕДИНЕНИИ?

ON (t1.ResourceName = t2.ResourceName AND t1.AccountId < t2.AccountId)

Может ли кто-нибудь посоветовать, возможно ли это или мы лаем не по тому дереву? Мы попытались максимально упростить исходный запрос, надеясь, что это упростит построение эквивалентного запроса LinqToEntities.

Примечание:

AccountId не уникален. У нас есть столбец Identity Id в таблице LocalResourceString. Однако существует уникальное ограничение как для AccountId, так и для ResourceName.


  • Похоже, что вы действительно хотите сделать, это выбрать записи, которые имеют самые большие AccountId для каждого ResourceName. Это правильно? 08.10.2012

Ответы:


1

‹РЕДАКТИРОВАТЬ› Похоже, что вы действительно хотите сделать, это выбрать записи, которые имеют самые большие AccountId для каждого ResourceName. Если предположить, что AccountId уникален, то:

localeStringResource =
    from e1 in localeStringResource
    group e1 by e1.ResourceName into grp
    select grp.Max(e => e.AccountID);

Здесь у вас левое внешнее соединение, поэтому вашему LINQ понадобится конструкция GroupJoin-SelectMany-DefaultIfEmpty. Join и GroupJoin преобразованы в равенство, но вы можете добавить остаток условия позже, перед DefaultIfEmpty:

localeStringResource =
    from e1 in localeStringResource
    join e2inner in localeStringResource
        on e1.ResourceName equals e2inner.ResourceName
        into grp
    from e2 in grp
        .Where(e => e1.AccountId < e.AccountId)
        .DefaultIfEmpty()
    where e2.ResourceName == null
    select e1;

Вот синтаксис метода для справки. Я использовал Tuple для передачи данных:

localeStringResource = localeStringResource
    .GroupJoin(
        localeStringResource,
        e1 => e1.ResourceName,
        e2 => e2.ResourceName,
        Tuple.Create)
    .SelectMany(pair => pair.Item2
        .Where(e2 => pair.Item1.AccountID < e2.AccountID)
        .DefaultIfEmpty()
        .Select( e2 => Tuple.Create(pair.Item1, e2)))
    .Where(pair => pair.Item2.ResourceName == null)
    .Select(pair => pair.Item1);
08.10.2012
  • Спасибо, Том. Я думаю, что ваш первоначальный ответ может быть билетом, хотя, как упоминалось в вашем EDIT, наши AccountId не уникальны (это таблица поиска, я изменил вопрос, чтобы добавить более подробную информацию о полях). Сейчас я пишу тест, чтобы посмотреть, что мы получим обратно. 08.10.2012
  • Редактирование должно работать, если пара {AccountId, ResourceName} уникальна. Проблема может возникнуть, если имеется несколько отдельных записей с одинаковыми AccountId и ResourceName, и в этом случае сокращенный запрос вернет только одну из них. Здесь не похоже, что это проблема. 08.10.2012

  • 2

    Попробуйте использовать синтаксис ANSI-82, поместив критерии соединения в предложение where:

    localeStringResource = from e1 in localeStringResource
                           from e2 in localeStringResource
                           where e1.ResourceName = e2.ResourceName &&
                                e1.AccountId < e2.AccountId
                           select e1;
    
    08.10.2012
  • Это будет выполнять внутреннее соединение, а не левое соединение. 08.10.2012
  • Спасибо, Джим, но нам нужно фильтровать по ResourceName == null, поэтому мы возвращаем только те строки, для которых у нас есть несколько значений. 08.10.2012
  • Новые материалы

    Создание кнопочного меню с использованием HTML, CSS и JavaScript
    Вы будете создавать кнопочное меню, которое имеет состояние наведения, а также позволяет вам выбирать кнопку при нажатии на нее. Финальный проект можно увидеть в этом Codepen . Шаг 1..

    Внедрите OAuth в свои веб-приложения для повышения безопасности
    OAuth — это широко распространенный стандарт авторизации, который позволяет приложениям получать доступ к ресурсам от имени пользователя, не раскрывая его пароль. Это позволяет пользователям..

    Классы в JavaScript
    class является образцом java Script Object. Конструкция «class» позволяет определять классы на основе прототипов с чистым, красивым синтаксисом. // define class Human class Human {..

    Как свинг-трейдеры могут использовать ИИ для больших выигрышей
    По мере того как все больше и больше профессиональных трейдеров и активных розничных трейдеров узнают о возможностях, которые предоставляет искусственный интеллект и машинное обучение для улучшения..

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

    Обзор: Машинное обучение: классификация
    Только что закончил третий курс курса 4 часть специализации по машинному обучению . Как и второй курс, он был посвящен низкоуровневой работе алгоритмов машинного обучения. Что касается..

    Разработка расширений Qlik Sense с qExt
    Использование современных инструментов веб-разработки для разработки крутых расширений Вы когда-нибудь хотели кнопку для установки переменной в приложении Qlik Sense? Когда-нибудь просили..