Зачем использовать 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()
для ловушки, если бы не были дочерние записи.