【问题标题】:Convert TSQL to Linq to Entities将 TSQL 转换为 Linq 到实体
【发布时间】:2016-01-20 05:46:09
【问题描述】:

我有 2 个名为 FileList 和 ExtensionsCategory 的表:

FileList
-------------------------------------------------------------
ID    Path         Extension

1     C:\7.pdf        pdf
2     D:\3.png        png
3     C:\1.mp3        mp3
4     D:\32.pdf       pdf

ExtensionsCategory 
------------------------------------------------------------
ID     Extension       Category

1        mp3           Multimedia
2        pdf           Document
3        png           Photo

表之间没有任何关系。

现在我想知道每个类别包含多少个文件? 我在 SSMS 中编写了以下 TSQL 查询并且工作正常:

SELECT 
     Category
    ,SUM(FileCount) AS TotalFileCount 
FROM    
    (SELECT 
         COUNT(*) AS FileCount
        ,(SELECT ExtensionsCategories.Category FROM ExtensionsCategories WHERE FileList.Extension = ExtensionsCategories.Extension) AS Category
    FROM FileList GROUP BY Extension) AS T1 GROUP BY Category

我想知道是否有任何改进的方法可以在没有加入的情况下做到这一点?

我尝试使用 Linq to Entities 编写它,这是我的代码,但我无法完成:

    var a = _dbContext.FileLists
        .Select(fl => new
        {
            Extension = fl.Extension,
            Count = _dbContext.FileLists.Count(),
            Cat =
                _dbContext.ExtensionsCategories.Where(w => w.Extension == fl.Extension).Select(s => s.Category)
        }).GroupBy(g => g.Extension);

【问题讨论】:

    标签: c# entity-framework linq tsql linq-to-entities


    【解决方案1】:

    这应该会给你正确的结果:-

    var result = from f in _dbContext.FileLists
                 group f by f.Extension into g
                 let firstCategory = _dbContext.ExtensionsCategories
                                               .FirstOrDefault(x => x.Extension == g.Key)
                 select new
                        {
                            Category = firstCategory != null ? firstCategory.Category : "",
                            TotalFileCount = g.Count()
                        };
    

    或者如果你需要Method Syntax:-

    var result = _dbContext.FileLists.GroupBy(e => e.Extension)
                  .Select(x =>
                      {
                          var firstCategory = _dbContext.ExtensionsCategories
                                               .FirstOrDefault(z => z.Extension == x.Key);
                          return new
                            {
                               Category = firstCategory != null ? firstCategory.Category : "",
                               TotalFileCount = x.Count()
                            };
                      });
    

    Fiddle 与 Linq-to-objects。

    更新:

    如果一个类别可以包含多个扩展名,那么您可以使用以下查询:-

    var result = extensionCat.GroupBy(x => x.Category)
                          .Select(x =>
                             new
                              {
                                  Category = x.Key,
                                  TotalFileCount = fileList.Count(f => x
                                                        .Any(z => z.Extension == f.Extension))
                              }
                          );
    

    【讨论】:

    • @MojtabaTajik - 哪些数据?
    • 抱歉,我忘记了广告链接:dotnetfiddle.net/FJCIm9 认为我们在同一类别中有多个扩展。
    • @MojtabaTajik - 好的,检查我的更新,它会工作。已更新小提琴。
    • @MojtabaTajik - 嘿,我再次更新了代码,这将更简单,也应该与 EF 一起使用。
    【解决方案2】:

    还有另一种方法可以更快地获得相同的结果。

    首先GroupBy 文件扩展名和CountGroupBy 元素选择器中。在那里,您还可以获得键的类别名称,在这种情况下是文件扩展名:

    var result =
        Files
        .GroupBy(x => x.Extension, (ext, fs) => new 
        { 
            Extension = ext, 
            Category = Categories.Single(c => c.Extension == ext).Name, 
            FileCount = fs.Count() 
        });
    

    这将产生以下查询:

    SELECT [t1].[Extension], (
        SELECT [t2].[Name]
        FROM [Category] AS [t2]
        WHERE [t2].[Extension] = [t1].[Extension]
        ) AS [Category], [t1].[value] AS [FileCount]
    FROM (
        SELECT COUNT(*) AS [value], [t0].[Extension]
        FROM [File] AS [t0]
        GROUP BY [t0].[Extension]
        ) AS [t1]
    

    另一方面,@RahulSingh 版本会产生这样的结果:

    -- Region Parameters
    DECLARE @p0 NVarChar(1000) = ''
    -- EndRegion
    SELECT 
        (CASE 
            WHEN EXISTS(
                SELECT TOP (1) NULL AS [EMPTY]
                FROM [Category] AS [t2]
                WHERE [t2].[Extension] = [t1].[Extension]
                ) THEN (
                SELECT [t4].[Name]
                FROM (
                    SELECT TOP (1) [t3].[Name]
                    FROM [Category] AS [t3]
                    WHERE [t3].[Extension] = [t1].[Extension]
                    ) AS [t4]
                )
            ELSE CONVERT(NVarChar(50),@p0)
         END) AS [Category], (
        SELECT COUNT(*)
        FROM [File] AS [t5]
        WHERE (([t1].[Extension] IS NULL) AND ([t5].[Extension] IS NULL)) OR (([t1].[Extension] IS NOT NULL) AND ([t5].[Extension] IS NOT NULL) AND ([t1].[Extension] = [t5].[Extension]))
        ) AS [TotalFileCount]
    FROM (
        SELECT [t0].[Extension]
        FROM [File] AS [t0]
        GROUP BY [t0].[Extension]
        ) AS [t1]
    

    我用 1.000.000 行测试了这两个查询,结果是:

    对比ToList 版本:

    在统计信息的最后几行中,您可以看到 short 版本快了大约 3 倍。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-09-13
      • 1970-01-01
      • 1970-01-01
      • 2013-05-03
      • 1970-01-01
      • 2012-07-26
      • 1970-01-01
      相关资源
      最近更新 更多