SELECT
table1.*
, table2.*
INNER JOIN table2 ON table2.SomeFkId = table1.SomeId
Это дает вам набор результатов, где дочерние строки в таблице2 вызывают дублирование, возвращая результаты таблицы1 для каждой дочерней строки в таблице2. Операторы отображения O / R должны дифференцировать экземпляры table1 на основе уникального ключевого поля, а затем использовать все столбцы table2 для заполнения дочерних экземпляров.
SELECT table1.*
SELECT table2.* WHERE SomeFkId = #
N + 1 - это место, где первый запрос заполняет первичный объект, а второй запрос заполняет все дочерние объекты для каждого из возвращенных уникальных первичных объектов.
Рассмотрим:
class House
{
int Id { get; set; }
string Address { get; set; }
Person[] Inhabitants { get; set; }
}
class Person
{
string Name { get; set; }
int HouseId { get; set; }
}
и таблицы с похожей структурой. Один запрос по адресу "22 Valley St" может вернуть:
Id Address Name HouseId
1 22 Valley St Dave 1
1 22 Valley St John 1
1 22 Valley St Mike 1
O / RM должен заполнить экземпляр Home с ID = 1, Address = "22 Valley St", а затем заполнить массив Inhabitants экземплярами People для Dave, John и Mike одним запросом.
Запрос N + 1 для того же адреса, который использовался выше, приведет к:
Id Address
1 22 Valley St
с отдельным запросом типа
SELECT * FROM Person WHERE HouseId = 1
и в результате получается отдельный набор данных, такой как
Name HouseId
Dave 1
John 1
Mike 1
и окончательный результат такой же, как указано выше для одного запроса.
Преимущества одиночного выбора в том, что вы получаете все данные заранее, что может быть именно тем, что вы в конечном итоге желаете. Преимущество N + 1 в том, что сложность запроса снижена, и вы можете использовать отложенную загрузку, когда дочерние наборы результатов загружаются только при первом запросе.