記事詳細


投稿日
2025年11月24日11時54分
タイトル

userIdのフィルターをかけるコード

内容

コードでは、 の取得時に ログイン中ユーザーの UserId でフィルタをかけたいということですね。
さらに、月別集計やページングにも対応できる形にリファクタリングします。paymentsNumMonth

1. 単純に フィルタを追加する場合UserId

var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
if (string.IsNullOrEmpty(userId))
{
    // 未ログイン時の処理
    return RedirectToAction("Login", "Account");
}

var paymentsNumMonth = _context.Payment
    .Include(p => p.SubjectName)
    .Where(p => p.UserId == userId) // ★ ユーザーIDでフィルタ
    .Where(p => p.Posted >= firstDayOfMonth && p.Posted <= lastDayOfMonth)
    .ToList();

2. 月別集計・ページング対応にリファクタリング

  • ポイント
    • IQueryableを使ってフィルタを段階的に適用(集計やページングに対応しやすい)
    • ページングは と を使用SkipTake
    • 集計は を使って月ごとにまとめられるGroupBy
using Microsoft.EntityFrameworkCore;
using System.Security.Claims;

public IActionResult Payments(int year, int month, int page = 1, int pageSize = 20)
{
    var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
    if (string.IsNullOrEmpty(userId))
    {
        return RedirectToAction("Login", "Account");
    }

    // 月初と月末を計算
    var firstDayOfMonth = new DateTime(year, month, 1);
    var lastDayOfMonth = firstDayOfMonth.AddMonths(1).AddDays(-1);

    // ベースクエリ(IQueryable)
    var query = _context.Payment
        .Include(p => p.SubjectName)
        .Where(p => p.UserId == userId) // ユーザーIDでフィルタ
        .Where(p => p.Posted >= firstDayOfMonth && p.Posted <= lastDayOfMonth)
        .OrderBy(p => p.Posted) // 並び順

        // IQueryableなのでまだDBにアクセスしない
        ;

    // ページング
    var totalCount = query.Count();
    var payments = query
        .Skip((page - 1) * pageSize)
        .Take(pageSize)
        .ToList();

    // 月別集計例(合計金額)
    var monthlySummary = _context.Payment
        .Where(p => p.UserId == userId)
        .GroupBy(p => new { p.Posted.Year, p.Posted.Month })
        .Select(g => new
        {
            Year = g.Key.Year,
            Month = g.Key.Month,
            TotalAmount = g.Sum(x => x.Amount)
        })
        .OrderByDescending(x => x.Year)
        .ThenByDescending(x => x.Month)
        .ToList();

    // ViewModelにまとめて返す
    var model = new PaymentsViewModel
    {
        Payments = payments,
        TotalCount = totalCount,
        Page = page,
        PageSize = pageSize,
        MonthlySummary = monthlySummary
    };

    return View(model);
}

// ViewModel例
public class PaymentsViewModel
{
    public List<Payment> Payments { get; set; }
    public int TotalCount { get; set; }
    public int Page { get; set; }
    public int PageSize { get; set; }
    public List<object> MonthlySummary { get; set; }
}

このリファクタリングのメリット

  1. UserId フィルタが共通化され、どの集計やページングにも適用される
  2. IQueryable を使うことで、必要な条件を後から追加可能
  3. ページング ( / ) と集計 () を分離して管理できるSkipTakeGroupBy
  4. 大量データでも効率的に動作(SQL に変換されて DB 側で処理)

もし希望があれば、このコードを 月別集計とページングを同時に行う API 形式 にもできます。
そうすれば SPA やフロントエンドからの非同期呼び出しにも対応できます。

この後、私が提案するのは 「共通フィルタを適用する拡張メソッド化」 です。
そうすると、どのコントローラでも のように書けます。
これを作りますか?query.FilterByUser(userId)

Powered by Froala Editor

添付画像

画像はありません
Genreのカテゴリ-名
Controllers
編集 | 記事一覧