24

現在、選択した日付で結果をグループ化するクエリを実行したいという問題に取り組んでいます。

この例では、次のような単純なモデルを想像してください。

public class User
{
      public DateTime LastLogIn {get; set;}
      public string Name {get; set;}
}

私が探している解決策は、Dateでログインしたユーザーの数を数えることです。 データベースではDateTimeは日付と時刻の両方のコンポーネントとともに格納されていますが、このクエリでは実際には日付のみを考慮しています。

私が現在持っているのはこれです:

    context.Users
            .Where((x.LastLogIn  >= lastWeek)    
                && (x.LastLogIn <= DateTime.Now))
            .GroupBy(x => EntityFunctions.TruncateTime(x.LastLogIn))
            .Select(x => new
            {
                Value = x.Count(),
                Day = (DateTime)EntityFunctions.TruncateTime(x.Key)
            }).ToList();

しかし上記は空のリストを返します。

最終目標は、Value(1日にログインしたユーザーの数)とDay(問題の日)を含むオブジェクトのリストを作成することです。

何かご意見は?

クエリを次のように変更すると

    context.Users
            .Where((x.LastLogIn  >= lastWeek)    
                && (x.LastLogIn <= DateTime.Now))
            .GroupBy(x => EntityFunctions.TruncateTime(x.LastLogIn))
            .Select(x => new
            {
                Value = x.Count(),
                Day = (DateTime)x.Key
            }).ToList();

これは単一の項目を持つリストを返すようになりました。Valueはwhere句に一致するユーザーの総数、Dayは一番最初の日です。それはまだ日によってグループ化することができるように思われていません

注意:上記のコードが正しいことがわかりました、私はちょうど何か他の間違ったことをしていました。

それが生成しているSQLは(私が例のためにそれを調整しているので、ここで非常にわずかな構文エラーであるかもしれないことに注意してください)

SELECT 
1 AS [C1], 
[GroupBy1].[A1] AS [C2], 
 CAST( [GroupBy1].[K1] AS datetime2) AS [C3]
FROM ( SELECT 
        [Filter1].[K1] AS [K1], 
        COUNT([Filter1].[A1]) AS [A1]
        FROM ( SELECT 
                 convert (datetime2, convert(varchar(255), [Extent1].[LastLogIn], 102) ,  102) AS [K1], 
                1 AS [A1]
                FROM [dbo].[Users] AS [Extent1]
                WHERE (([Extent1].[LastLogIn] >= @p__linq__1) AND ([Extent1].[LastLogIn] <= @p__linq__2)
        )  AS [Filter1]
       GROUP BY [K1]
)  AS [GroupBy1] 


  • クエリは問題ないようです。交換するとゼロ以外の値に戻りますかGroupByストレートでCount()? - dasblinkenlight
  • 単純なカウントで実行すると、where節に一致すると予想されるカウントが返されます。それは、それを殺しているグループ化のようです。 - Thewads
  • 交換してみましたかDay = (DateTime)EntityFunctions.TruncateTime(x.Key)Day = x.Key?日付はグループ化のためにすでに切り捨てられているので、それは同じであるべきです。 - dasblinkenlight
  • さて、それを削除するといくつかのことが変わりました。今度は単一の項目を持つリストを返します。詳細で質問を更新します - Thewads
  • 外側では、これはEFのバグのように見えます。何が起こっているのかを確認するために、SQLをキャプチャしてDBで直接実行してみましたか。 - dasblinkenlight

4 답변


26

あなたは第二を必要としないTruncateTimeそこで:

context.Users
    .Where((x.LastLogIn  >= lastWeek) && (x.LastLogIn <= DateTime.Now))
    .GroupBy(x => DbFunctions.TruncateTime(x.LastLogIn))
    .Select(x => new
    {
        Value = x.Count(),
        // Replace the commented line
        //Day = (DateTime)DbFunctions.TruncateTime(x.Key)
        // ...with this line
        Day = (DateTime)x.Key
    }).ToList();

GroupByから時間を切り捨てましたDateTimeもうすでに電話する必要はありません。

使用するDbFunctions.TruncateTimeアセンブリを参照する必要があります。System.Data.Entity含むusing System.Data.Entity;

注意:の廃止予定に対処するために編集EntityFunctions


  • .GroupBy(x => EntityFunctions.TruncateTime(x.LastLogIn))ここでは日付ごとのグループ化を検討するための重要な要素です。 - sandeep talabathula
  • @dasblinkenlightこんにちは、count = 0の日を含めるためにあなたのソリューションにどんな変更を加えなければなりませんか?ログインがない場合でも、時間枠内のすべての日を返す必要があります。ありがとう。 - Patrick
  • @パトリック私はあなたがそれを行うことができるとは思わない:LINQはそれがデータベース内にない限り結果を返しません。結果を辞書に変換してから、一度に1日ずつ日付の範囲を調べ、使用可能な場合は辞書からデータを取得できます。 - dasblinkenlight
  • @ dasblinkenlight oohhh :(わかりました、ありがとう。 - Patrick

2

これを試して:

 .GroupBy(x => new {Year = x.LastLogIn.Year, Month = x.LastLogIn.Month, Day = x.LastLogIn.Day)
                .Select(x => new
                {
                    Value = x.Count(),
                    Year = x.Key.Year,
                    Month = x.Key.Month,
                    Day = x.Key.Day
                })


  • ちょっと、これは上で説明されたのと同じ状況にあります、それはそれがすべてのアイテムの数を持っている単一のアイテムでリストを返すことで、 - Thewads
  • 機能している可能性はありますが(どういうわけか厄介ですが)、元のクエリが機能しないのはなぜですか。 - Alireza

1

簡単にできます。

yourDateList.GroupBy(i => i.ToString("yyyyMMdd"))
             .Select(i => new
             {
                 Date = DateTime.ParseExact(i.Key, "yyyyMMdd", CultureInfo.InvariantCulture, DateTimeStyles.None),
                 Count = i.Count()
             });


  • 「そうだ」と思われます。あまり有効ではありません。しかし、私はこのアプローチを何度も何度も使って素晴らしい成功を収めています。特に「yyyyMMdd」という観点から来ています。データを渡すときにSQL Serverで広く受け入れられている日付形式です。 - pimbrouwers

1

1行でも実行できます。

var b = (from a in ctx.Candidates select a)
            .GroupBy(x => x.CreatedTimestamp.Date).Select(g => new { Date=(g.Key).ToShortDateString(), Count = g.Count() });

関連する質問

最近の質問