简体   繁体   中英

Distinct count with group fails though count is working fine

I'm trying to convert a sql server query to Mongo C# driver LINQ . I have a table with multiple entries for each guid and each entry has different code value. I need get a distinct count of guids for each code. I'm able to do Count() in LINQ but when I do Distinct().Count() I get the following exception:

Specified method is not supported

Following is the T-SQL I'm trying to convert:

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

Following is my 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();

Please tell what am I doing wrong here.

The key is that some Linq-to-Object constructs are not supported in Linq-to-SQL/EF. One approach is to grab the data with your WHERE using Linq-to-SQL/EF and then do the rest of the operations on the objects that come back in memory with Linq-to-Objects.

Without your actual data source it's impossible to test, but the following code illustrates how this can be done. Notice the first .ToList() call, which will fetch the results from the database, then the rest of the Linq query is done in memory on the returned objects:

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; }
}

i believe this will give the result you want. nothing is done on the clientside as ToList is called at the very end to materialize the results. also, since you're already fitering by code == 0 grouping is done on the guid field instead.

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();
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM