Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/307.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/entity-framework/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 通过sql将Linq转换为实体顺序_C#_Entity Framework_Linq - Fatal编程技术网

C# 通过sql将Linq转换为实体顺序

C# 通过sql将Linq转换为实体顺序,c#,entity-framework,linq,C#,Entity Framework,Linq,我正在使用EF和Linq-to-entities进行一些测试,以尝试提高我的应用程序性能 我只是注意到(对我来说)一些奇怪的事情,我无法解释,也无法判断是否会产生相当大的开销 这是我的linq: var result = from n in query orderby n.PersonId select new { id = n.Id, appointmentId = n.AppointmentId,

我正在使用
EF
Linq-to-entities
进行一些测试,以尝试提高我的应用程序性能

我只是注意到(对我来说)一些奇怪的事情,我无法解释,也无法判断是否会产生相当大的开销

这是我的linq:

var result = from n in query
        orderby n.PersonId
        select new
        {
            id = n.Id,
            appointmentId = n.AppointmentId,
            message = n.Message,
            wasRead = n.Read,
            canDismiss = (n.Appointment.Status != AppointmentStatus.Waiting),
            date = n.IssueDateUtc
        };
这是生成的sql:

SELECT 
    [Project1].[Id] AS [Id], 
    [Project1].[AppointmentId] AS [AppointmentId], 
    [Project1].[Message] AS [Message], 
    [Project1].[Read] AS [Read], 
    [Project1].[C1] AS [C1], 
    [Project1].[IssueDateUtc] AS [IssueDateUtc]
    FROM ( SELECT 
        [Extent1].[Id] AS [Id], 
        [Extent1].[Read] AS [Read], 
        [Extent1].[Message] AS [Message], 
        [Extent1].[IssueDateUtc] AS [IssueDateUtc], 
        [Extent1].[AppointmentId] AS [AppointmentId], 
        [Extent1].[PersonId] AS [PersonId], 
        CASE WHEN ( NOT ((1 = [Extent2].[Status]) AND ([Extent2].[Status] IS NOT NULL))) THEN cast(1 as bit) WHEN (1 = [Extent2].[Status]) THEN cast(0 as bit) END AS [C1]
        FROM  [dbo].[Notification] AS [Extent1]
        LEFT OUTER JOIN [dbo].[Appointment] AS [Extent2] ON [Extent1].[AppointmentId] = [Extent2].[Id]
        WHERE [Extent1].[PersonId] = @p__linq__0
    )  AS [Project1]
    **ORDER BY [Project1].[PersonId] ASC**
我不理解将结果分组到另一个投影(
Project1
)中的必要性,尽管这似乎很好:

SELECT 
        [Extent1].[Id] AS [Id], 
        [Extent1].[Read] AS [Read], 
        [Extent1].[Message] AS [Message], 
        [Extent1].[IssueDateUtc] AS [IssueDateUtc], 
        [Extent1].[AppointmentId] AS [AppointmentId], 
        [Extent1].[PersonId] AS [PersonId], 
        CASE WHEN ( NOT ((1 = [Extent2].[Status]) AND ([Extent2].[Status] IS NOT NULL))) THEN cast(1 as bit) WHEN (1 = [Extent2].[Status]) THEN cast(0 as bit) END AS [C1]
        FROM  [dbo].[Notification] AS [Extent1]
        LEFT OUTER JOIN [dbo].[Appointment] AS [Extent2] ON [Extent1].[AppointmentId] = [Extent2].[Id]
        WHERE [Extent1].[PersonId] = @p__linq__0
        **ORDER BY [Extent1].[PersonId] ASC**
我发现ef和linq都生成了大量有问题的sql,我开始怀疑我是否最好只编写原始sql

问题是:生成的sql额外代码位是否值得担心?为什么这一预测是必要的

编辑以添加新的linq

正如在注释中提到的,可能是由于后续的查询正在运行而导致冗长。我重写了linq以仅使用一个查询对象,结果仍然相同:

dbSet.Where(n => n.PersonId == id).Select(n => new
            {
                Id = n.Id,
                AppointmentId = n.AppointmentId,
                Message = n.Message,
                Read = n.Read,
                CanBeDismissed = (n.Appointment.Status != AppointmentStatus.Waiting),
                IssueDate = n.IssueDateUtc
            }).OrderBy(n => n.Id).ToList();
执行计划(两个
sqls
相同)

编辑2

刚从一个简单的计数中得到这个查询

dbSet.Count(x => x.Id == 1 && x.Read == false);

SELECT 
[GroupBy1].[A1] AS [C1]
FROM ( SELECT 
    COUNT(1) AS [A1]
    FROM [dbo].[Notification] AS [Extent1]
    WHERE ([Extent1].[PersonId] = 19) AND (0 = [Extent1].[Read])
)  AS [GroupBy1]
预期:

SELECT 
    COUNT(1) AS [A1]
    FROM [dbo].[Notification] AS [Extent1]
    WHERE ([Extent1].[PersonId] = 19) AND (0 = [Extent1].[Read])

我不知道这些包装器来自何方,也不知道为什么。

我在我的机器上组装了一个小样本项目。实际导致第一个示例中出现投影的是对CanBeDismissed字段的条件计算,当SQL中出现时,会出现一种情况。如果不考虑这一点,实体框架将不会进行额外的投影

因此,通过条件检查:

db.Notifications
    .Where(n => n.AppointmentId == 1)
    .OrderBy(n => n.Id)
    .Select(n => new
    {
        Id = n.Id,
        Message = n.Message,
        HasMessage = n.Message != null
    }).ToList();
生成的SQL是:

SELECT 
    [Project1].[Id] AS [Id], 
    [Project1].[Message] AS [Message], 
    [Project1].[C1] AS [C1]
    FROM ( SELECT 
        [Extent1].[Id] AS [Id], 
        [Extent1].[Message] AS [Message], 
        CASE WHEN ([Extent1].[Message] IS NOT NULL) THEN cast(1 as bit) ELSE cast(0 as bit) END AS [C1]
        FROM [dbo].[Notifications] AS [Extent1]
        WHERE 1 = [Extent1].[AppointmentId]
    )  AS [Project1]
    ORDER BY [Project1].[Id] ASC
让我添加生成的执行计划,以供以后参考:

如果你不考虑:

db.Notifications
    .Where(n => n.AppointmentId == 1)
    .OrderBy(n => n.Id)
    .Select(n => new
    {
        Id = n.Id,
        Message = n.Message
    }).ToList();
EF未进行任何投影:

SELECT 
    [Extent1].[Id] AS [Id], 
    [Extent1].[Message] AS [Message]
    FROM [dbo].[Notifications] AS [Extent1]
    WHERE 1 = [Extent1].[AppointmentId]
    ORDER BY [Extent1].[Id] ASC
这就是为什么。这同样适用于您的
count
示例:如果发生任何分组,EF将添加一个额外的投影,使查询更加详细。但重要的一点是,正如对您的问题的评论中所讨论的,这不会影响性能,不必担心这个额外的预测

现在让我通过添加以下查询的执行计划来证明这一点,我刚刚从第一个查询中删除了pojection,并将orderby移动到了内部查询:

SELECT
[Extent1].[Id] AS [Id], 
[Extent1].[Message] AS [Message], 
CASE WHEN ([Extent1].[Message] IS NOT NULL) THEN cast(1 as bit) ELSE cast(0 as bit) END AS [C1]
FROM [dbo].[Notifications] AS [Extent1]
WHERE 1 = [Extent1].[AppointmentId]
ORDER BY [Extent1].[Id] ASC

这是完全相同的-没有增加额外的任务,成本分布保持不变。SQL查询优化器将很好地优化这些项目

所以,再次强调,不要担心预测——它们不会伤害你,尽管我同意它们看起来和有时是不必要的冗长。但这里有两件事可能会对你有所帮助:

性能问题:

首先,如果您的查询遇到性能问题,请查看您发布的执行计划中为什么会出现
聚集索引扫描。对于某些索引问题来说,这并不总是一个迹象,但通常是这样。你的问题可能就在这里

摆脱不必要的投影:

如果您仍然希望在所有(或至少更多)情况下消除这些投影,那么EntityFrameworkCore1.0——它实际上产生了比EF6更好的SQL。可能值得考虑迁移到它,但请注意,它并没有EF 6提供的所有功能,因此,如果您使用的是EF Core 1.0不提供的功能,那么它可能不是一个选项。但它将与完整的.NETFramework4.x一起工作

下面是一个例子,当我执行我答案的第一条LINQ语句时,EF Core 1.0会产生什么:

SELECT [n].[Id], [n].[Message], CASE
    WHEN [n].[Message] IS NULL
    THEN CAST(0 AS BIT) ELSE CAST(1 AS BIT)
END
FROM [Notifications] AS [n]
WHERE ([n].[Id] = 1) AND ([n].[Id] = 1)
ORDER BY [n].[Id]

我假设
query
是另一个linqtosql查询,这就是您在投影中看到的嵌套查询。这正是你对LINQ所做的。如果您想摆脱它,只需将
OrderBy
Select
添加到
query
中即可。但是,如果使用后续LINQ查询可以使代码更干净,请不要担心。。。投影有最小的开销(如果有的话)。如果有疑问,比较执行计划。但是,如果您看到性能问题,它肯定不是由该投影引起的。。。我发现LINQtoSQL生成了出色的(但通常是冗长的)SQL查询,在复杂的场景中更是如此。我认为这比大多数程序员所能达到的效果要好。当然,它还需要编写良好的LINQ查询。因此,您可以仔细检查生成的SQL。。。但总的来说,别担心,LINQ通常在何时使用连接、交叉应用程序或任何性能最好的东西方面都会做出很好的选择,事实上,我经常从LINQ生成的SQL中学到一些新东西;)我也一直在学习新的东西。我只是担心,因为我对sgdb研究得不多,我的产品也在增长,现在我花时间分析数据库访问,我看到了非常糟糕的代码,只是重写了表达式,我就能够将性能提高60%左右。无论如何,我只使用一个查询重写了linq,结果是一样的。我会把它添加到问题中,请检查一下。我认为额外的代码是因为使用了匿名类型而生成的。不要担心投影,它不是很糟糕(执行)SQL只是有点冗长。。。尝试在SQL Server Management Studio中执行这两个查询,并激活执行计划和统计信息。。。你会发现结果几乎是一样的。至于如何摆脱投影,我明天会给你一个样本,如果没有其他人加入,因为我现在必须离开。但是让我知道
dbSet.where()
中的
where
的确切作用。我在代码中添加了
where
n=>n.PersonId==id
)。谢谢,非常好,谢谢。我认为进行索引扫描是因为必须检查每一行的fk列是否为X。在解决了这个问题之后,您可以在我发布的执行计划中看到,db似乎进行了一次索引搜索,以获取id为X的行来执行