【问题标题】:Distinct count with group fails though count is working fine尽管计数工作正常,但组的不同计数失败
【发布时间】:2019-12-03 09:54:41
【问题描述】:

我正在尝试将 sql server 查询转换为 Mongo C# driver LINQ。 我有一个表,每个 guid 都有多个条目,每个条目都有不同的 code 值。 我需要为每个代码获取不同的 guid 计数。我可以在 LINQ 中执行 Count(),但是当我执行 Distinct().Count() 时,出现以下异常:

不支持指定的方法

以下是我要转换的 T-SQL:

SELECT a.code, substring(convert(varchar, a.create_Date, 107), 1, 6) as create_Date,count(distinct  a.guid) as mycount
FROM table1 a (nolock) 
WHERE a.code = 0 
AND a.create_Date BETWEEN DateAdd(day,   -2  , @startDate) AND DateAdd(day, 1, @startDate)
GROUP BY a.code, substring(convert(varchar, a.create_Date, 107), 1, 6)
Order by 1

以下是我的 LINQ:

    var result = from tb in collection3.AsQueryable()
                 where
                 tb.code == 0
                 && tb.create_Date > rptGte
                 && tb.create_Date < rptLt
                 group tb by new
                 {
                     tb.code,
                     create_Date = tb.create_Date.DayOfYear
                 } into g
                 select new
                 {
                     code = g.Key.code,
                     create_Date = g.Key.create_Date,
                     mycount = g.Select(x => x.guid).Distinct().Count() //distinct not working here
                 };

    var resultList = rpt.ToList();

请告诉我在这里做错了什么。

【问题讨论】:

标签: c# mongodb linq mongodb-.net-driver mongodb-csharp-2.0


【解决方案1】:

关键是 Linq-to-SQL/EF 不支持某些 Linq-to-Object 构造。一种方法是使用 Linq-to-SQL/EF 使用 WHERE 获取数据,然后使用 Linq-to-Objects 对返回到内存中的对象执行其余操作。

如果没有您的实际数据源,则无法进行测试,但以下代码说明了如何进行测试。注意第一个 .ToList() 调用,它将从数据库中获取结果,然后 Linq 查询的其余部分在内存中对返回的对象完成:

public List<Result> GetGroupedResults(DateTime date)
{
    return table1
        .Select(x => new {x.code, x.create_Date, x.guid })
        .Where(x => 
            x.code == 0 && 
            x.create_Date > date.AddDays(-2) && 
            x.create_Date < date.AddDays(1))
        .ToList() // Fetch from database
        .GroupBy(x => new
        {
            Code = x.code, 
            CreateDateStr = x.create_Date.ToString("MMM dd")
        })
        .OrderBy(g => g.Key.Code)
        .Select(g => new Result
        {
            Code = g.Key.Code, 
            DateStr = g.Key.CreateDateStr, 
            Count = g.Select(x => x.guid).Distinct().Count()
        })
        .ToList();
}

public class Result
{
    public int Code { get; set; }
    public string DateStr { get; set; }
    public int Count { get; set; }
}

【讨论】:

  • 我知道的没错!这正是我想要避免的。这里的痛苦是有太多的数据我想避免在应用程序端进行操作。但如果没有其他办法,我想我将不得不走这条路。谢谢:)
  • 是的,您需要引入未分组的数据,但是如果您担心您的云出口成本,它将被 3 列和您的 where 子句过滤。跨度>
  • @gatsby 如果我的回答有帮助,请接受并选择投票。
  • 我正在等待是否有另一个答案可以帮助我在数据库端本身处理这个问题。谢谢!不过,我肯定会赞成你的回答,但我对此没有足够的声誉!
【解决方案2】:

我相信这会给你想要的结果。客户端没有做任何事情,因为在最后调用ToList 以实现结果。另外,由于您已经通过 code == 0 进行了调整,因此分组是在 guid 字段上完成的。

using MongoDB.Entities;
using MongoDB.Entities.Core;
using System;
using System.Linq;

namespace StackOverflow
{
    public class TeeBee : Entity
    {
        public int code { get; set; }
        public DateTime create_Date { get; set; }
        public string guid { get; set; }
    }

    public class Program
    {
        private static void Main(string[] args)
        {
            new DB("test", "localhost");

            (new[] {
                new TeeBee { code = 0, create_Date = DateTime.UtcNow, guid = "xxx"},
                new TeeBee { code = 0, create_Date = DateTime.UtcNow, guid = "xxx"},
                new TeeBee { code = 0, create_Date = DateTime.UtcNow, guid = "yyy"},
                new TeeBee { code = 1, create_Date = DateTime.UtcNow, guid = "xxx"},
            }).Save();

            var result = DB.Queryable<TeeBee>() // for official driver use: collection.AsQueryable()

                           .Where(tb =>
                                  tb.code == 0 &&
                                  tb.create_Date <= DateTime.UtcNow.AddDays(1) &&
                                  tb.create_Date >= DateTime.UtcNow.AddDays(-1))

                           .GroupBy(tb => tb.guid,
                                   (g, tbs) => new
                                   {
                                       tbs.First().code,
                                       tbs.First().create_Date,
                                       uniqueGuids = tbs.Select(tb => tb.guid).Distinct()
                                   })

                           .Select(x => new
                           {
                               Code = x.code,
                               DateStr = x.create_Date.DayOfYear,
                               Count = x.uniqueGuids.Count()
                           })

                           .ToList();
        }
    }
}

【讨论】:

  • 感谢您的回答,但我在这里面临两个问题:1.)您已按日期时间字段 create_Date 分组,我想按该字段的日期部分分组。 2.) 当我应用您的代码时,结果列表中只有一项。
  • @gatsby 如果您可以从 mongodb 中添加一些示例数据以及您需要的输出,那将会有所帮助。这样我就可以将该测试数据插入到 mongodb 并尝试得出所需的最终结果。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-13
  • 1970-01-01
  • 1970-01-01
  • 2014-01-17
相关资源
最近更新 更多