Зачем использовать LINQ Join для простого отношения "один-много"?

Я использую LINQ to SQL и Entity Framework в течение нескольких лет, и я всегда сопоставлял свои отношения с базой данных для создания соответствующих свойств навигации. И я всегда использую свойства навигации.

Я что-то пропустил?

Если у меня есть отношение типа Category->Products one-many type, я бы использовал

var redProducts = context.Category.Single(c => c.Name = "red").Products;

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

var employer = from category in context.Categories
               join product in context.Products
               on category.CategoryId equals product.CategoryId
               where category.Name == "red"
               select product;

Итак - почему? Каковы преимущества использования этого синтаксиса Join?

Ответы

Ответ 1

Обычно это ошибка.

@George правильно, что ваши два примера функционально отличаются способом, который не имеет ничего общего с join vs non join. Но вы так же легко можете написать:

var redProducts = context.Category
                         .Where(c => c.Name == "red")
                         .SelectMany(c => c.Products);

..., который функционально идентичен (но превосходит читаемость и поддерживаемость POV) для вашего примера join.

Ответ 2

Это может быть связано с переносом старого кода на linq2sql.

Однако два фрагмента кода не являются функционально равными.

Single будет генерировать исключение, а join дает пустую коллекцию в случае отсутствия записи.

Таким образом, равный код без использования объединений будет:

from c in context.Categories where c.Name == "red" from p in c.Products select p;

или

context.Categories.Where(c=>c.Name == "red").SelectMany(c=>c.Products);

Ответ 3

Соединения, вероятно, более распространены для людей, исходящих из реляционного мышления, а не объектно-ориентированного. Если вы думаете о своем проблемном пространстве с объективной ориентированной точки зрения, гораздо более естественно работать с отношениями, в которых вы можете прорисовать через навигацию: Employee.Customers.Orders.OrderItems.OrderItem, чем иметь дело с кучей объединений. В оригинальном техническом документе ADO.vNext была хорошая работа по обсуждению преимуществ использования модели и ассоциаций, а не для взаимодействия с вашими концептуальными моделями. К сожалению, я не могу найти этот документ на этом этапе.

Для меня, соединения лучше всего использовать, когда у вас нет естественных связей между сущностями. Например, если вы пытаетесь присоединиться к элементам неестественных ключей (т.е. присоединяться к Customer.State и Shipping.State), вы должны использовать синтаксис соединения (или SelectMany), а не создавать ассоциации между вашими объектами в этом случае.

Одна вещь, о которой нужно знать, это то, что синтаксис соединения и использование ассоциаций могут вызывать различия в типах объединений, которые генерируются провайдером. Как правило, Join переводит на внутреннее соединение и исключает элементы, в которых нет совпадений с обеих сторон соединения. Чтобы выполнить (левое) внешнее соединение, вы используете расширение DefaultIfEmpty.

Перемещение по ассоциациям в отношениях 1-0.. *, с другой стороны, обычно преобразуется в соединения "Прямое внешнее", потому что дочерняя коллекция может быть законно пустой, и вы хотели бы включить родителя, даже если ребенок не существует. Вы использовали бы !Any() для ловушки, если бы не были дочерние записи.