#c# #sql #sql-server #linq #entity-framework
#c# #sql #sql-сервер #linq #entity-framework
Вопрос:
Это действительно сводит меня с ума, и я не могу понять, почему надеюсь, что кто-нибудь может дать мне небольшой намек, почему это так себя ведет. У меня есть 4 таблицы
1-я группа из этих 2 таблиц и может дать мне чистый и приятный T-SQL (образец по этой ссылке)
public class Standard
{
public Standard()
{
Students = new List<Student>();
}
public int StandardId { get; set; }
public string StandardName { get; set; }
public string Description { get; set; }
public virtual ICollection<Student> Students { get; set; }
}
public class Student
{
public Student() { }
public int StudentId { get; set; }
public string StudentName { get; set; }
public virtual Standard Standard { get; set; }
}
С приведенными выше таблицами и я использую этот
LINQ
List<Student> student = context.student.ToList();
var r = from ord in context.student.Include("standard")
select ord;
Вывод
SELECT
[Extent1].[StudentId] AS [StudentId],
[Extent1].[StudentName] AS [StudentName],
[Extent2].[StandardId] AS [StandardId],
[Extent2].[StandardName] AS [StandardName],
[Extent2].[Description] AS [Description]
FROM [dbo].[Students] AS [Extent1]
LEFT OUTER JOIN [dbo].[Standards] AS [Extent2] ON [Extent1].[Standard_StandardId] = [Extent2].[StandardId]
Но со 2-й группой
public partial class Cust_ProfileTbl
{
public Cust_ProfileTbl()
{
balance = new List<BP_BalanceTbl>();
}
[Key]
public virtual long bintAccountNo { get; set; }
public string varCardNo { get; set; }
public virtual ICollection<BP_BalanceTbl> balance { get; set; }
}
public class BP_BalanceTbl
{
public BP_BalanceTbl() { }
public virtual long bintAccountNo { get; set; }
[Key]
public int intid { get; set; }
public virtual Cust_ProfileTbl profile { get; set; }
}
с помощью этого LINQ
List<Cust_ProfileTbl> profile = context.profile.ToList();
var rs = from ord in context.profile.Include("balance")
select ord;
Вывод
SELECT
[Project1].[C1] AS [C1],
[Project1].[bintAccountNo] AS [bintAccountNo],
[Project1].[varCardNo] AS [varCardNo],
[Project1].[C2] AS [C2],
[Project1].[intid] AS [intid],
[Project1].[bintAccountNo1] AS [bintAccountNo1]
FROM ( SELECT
[Extent1].[bintAccountNo] AS [bintAccountNo],
[Extent1].[varCardNo] AS [varCardNo],
1 AS [C1], --Why it generate this>?
[Extent2].[intid] AS [intid],
[Extent2].[bintAccountNo] AS [bintAccountNo1],
CASE WHEN ([Extent2].[intid] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C2] --Why it generate this>?
FROM [dbo].[Cust_ProfileTbl] AS [Extent1]
LEFT OUTER JOIN [dbo].[BP_BalanceTbl] AS [Extent2] ON [Extent1].[bintAccountNo] = [Extent2].[bintAccountNo]
) AS [Project1]
ORDER BY [Project1].[bintAccountNo] ASC, [Project1].[C2] ASC
Вопросы
- Почему во 2-м LINQ он генерирует C1?
- Почему во 2-м LINQ есть этот случай строки, КОГДА ([Extent2] .[intid] РАВНО НУЛЮ) ЗАТЕМ ПРИВЕДИТЕ (NULL КАК int) ЕЩЕ 1 КОНЕЦ КАК [C2] — почему он генерирует это>?
- Почему 2-й вывод такой сложный?
Ответ №1:
-
Столбец C1, по-видимому, не имеет отношения к запросу — это может быть оптимизация или защита, которая происходит автоматически, чтобы LINQ не мог случайно создать что-то недопустимое — или, возможно, чтобы первая строка не могла случайно иметь нулевые значения.
-
Столбец C2 генерируется как защита от нулевого значения, поскольку значение присваивается как первичный ключ (что означает, что оно не может быть пустым). Поскольку вы выполняете ЛЕВОЕ ВНЕШНЕЕ СОЕДИНЕНИЕ, значения слева могут не иметь записей объединения, но все равно должны отображать допустимую строку для левой информации.
-
Запрос выглядит более сложным, потому что он создает эту дополнительную информацию во временной таблице перед выбором результатов. Возможно, он формулирует запрос таким образом только потому, что это единственный способ, которым он знает, как сгенерировать его с помощью кода — или, может быть, он достаточно умен, чтобы знать, что этот запрос немного более оптимален для механизма запросов (я бы, вероятно, не стал делать ставку на это).
Ответ №2:
В первом случае вы выполняете Include для простого свойства навигации (таким образом, это можно сделать с помощью простого внешнего соединения слева, и каждая строка в ответе будет материализована как объект в результате), во втором случае включается коллекция, поэтому несколько строк из результата должны быть объединены в единый объект и его свойство collection. Таким образом, SQL-запрос должен быть написан следующим образом, чтобы: 1. Все строки, которые будут объединены в единый объект, будут извлекаться последовательно 2. Упростить процесс определения групповых границ 3. Уменьшить дублирование данных Некоторые части сгенерированного SQL можно исключить в этом простом случае, но они используются в более сложных запросахкогда включено несколько свойств коллекции и т. д.