SkyoceanHome
Home
Privacy
ダウンロード
SkyShop
Updated Information
チュートリアルコード集
記事編集
日付
ジャンルのカテゴリ―名
名前を選択して下さい。
Contexts
Controllers
Databases
Htmls
JavaScripts
Models
MVCTutorials
Others
Styles
Views
タイトル
内容の要旨
<p style="border: 0px; border-collapse: collapse; border-spacing: 0px; list-style-position: initial; list-style-image: initial; list-style-type: revert; margin: revert; padding: revert; -webkit-line-clamp: revert; color: rgb(17, 17, 17); font-family: Roboto, Helvetica, sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgb(249, 249, 249); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;" data-pasted="true">コードでは、 の取得時に <strong style="font-weight: 700;">ログイン中ユーザーの <code style="border: 1px solid rgb(221, 221, 221); border-radius: 4px; padding: 1px 4px; background: rgb(255, 255, 255); font: 14px / 20px monospace;">UserId</code></strong> でフィルタをかけたいということですね。<br>さらに、<strong style="font-weight: 700;">月別集計やページングにも対応できる形</strong>にリファクタリングします。<code style="border: 1px solid rgb(221, 221, 221); border-radius: 4px; padding: 1px 4px; background: rgb(255, 255, 255); font: 14px / 20px monospace;">paymentsNumMonth</code></p><h2 style="border: 0px; border-collapse: collapse; border-spacing: 0px; list-style-position: initial; list-style-image: initial; list-style-type: revert; margin: revert; padding: revert; font: 18px / 24px Roboto, sans-serif; color: rgb(17, 17, 17); letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgb(249, 249, 249); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">1. 単純に フィルタを追加する場合<code style="border: 1px solid rgb(221, 221, 221); border-radius: 4px; padding: 1px 4px; background: rgb(255, 255, 255); font: 14px / 20px monospace;">UserId</code></h2><pre data-priority="2" style="color: rgb(17, 17, 17); font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(249, 249, 249); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;"><code style="border: 1px solid rgb(221, 221, 221); border-radius: 8px; padding: 12px 20px; background: rgb(255, 255, 255); font: 14px / 20px monospace; display: block; white-space: pre-wrap; margin-right: 20px;"><span style="color: rgb(215, 58, 73);">var</span> userId = User.FindFirstValue(ClaimTypes.NameIdentifier); <span style="color: rgb(215, 58, 73);">if</span> (<span style="color: rgb(227, 98, 9);">string</span>.IsNullOrEmpty(userId)) { <span style="color: rgb(106, 115, 125);">// 未ログイン時の処理</span> <span style="color: rgb(215, 58, 73);">return</span> RedirectToAction(<span style="color: rgb(3, 47, 98);">"Login"</span>, <span style="color: rgb(3, 47, 98);">"Account"</span>); } <span style="color: rgb(215, 58, 73);">var</span> paymentsNumMonth = _context.Payment .Include(p => p.SubjectName) .Where(p => p.UserId == userId) <span style="color: rgb(106, 115, 125);">// ★ ユーザーIDでフィルタ</span> .Where(p => p.Posted >= firstDayOfMonth && p.Posted <= lastDayOfMonth) .ToList(); </code></pre><h2 style="border: 0px; border-collapse: collapse; border-spacing: 0px; list-style-position: initial; list-style-image: initial; list-style-type: revert; margin: revert; padding: revert; font: 18px / 24px Roboto, sans-serif; color: rgb(17, 17, 17); letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgb(249, 249, 249); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">2. 月別集計・ページング対応にリファクタリング</h2><ul style="border: 0px; border-collapse: collapse; border-spacing: 0px; list-style-position: initial; list-style-image: initial; list-style-type: revert; margin: revert; padding: revert; color: rgb(17, 17, 17); font-family: Roboto, Helvetica, sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgb(249, 249, 249); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;"><li style="border: 0px; border-collapse: collapse; border-spacing: 0px; list-style-position: initial; list-style-image: initial; list-style-type: revert; margin-top: revert; margin-right: revert; margin-bottom: 8px; margin-left: revert; padding: revert;"><strong style="font-weight: 700;">ポイント</strong><ul style="border: 0px; border-collapse: collapse; border-spacing: 0px; list-style-position: initial; list-style-image: initial; list-style-type: revert; margin: revert; padding: revert;"><li style="border: 0px; border-collapse: collapse; border-spacing: 0px; list-style-position: initial; list-style-image: initial; list-style-type: revert; margin-top: revert; margin-right: revert; margin-bottom: 8px; margin-left: revert; padding: revert;"><code style="border: 1px solid rgb(221, 221, 221); border-radius: 4px; padding: 1px 4px; background: rgb(255, 255, 255); font: 14px / 20px monospace;">IQueryable</code>を使ってフィルタを段階的に適用(集計やページングに対応しやすい)</li><li style="border: 0px; border-collapse: collapse; border-spacing: 0px; list-style-position: initial; list-style-image: initial; list-style-type: revert; margin-top: revert; margin-right: revert; margin-bottom: 8px; margin-left: revert; padding: revert;">ページングは と を使用<code style="border: 1px solid rgb(221, 221, 221); border-radius: 4px; padding: 1px 4px; background: rgb(255, 255, 255); font: 14px / 20px monospace;">Skip</code><code style="border: 1px solid rgb(221, 221, 221); border-radius: 4px; padding: 1px 4px; background: rgb(255, 255, 255); font: 14px / 20px monospace;">Take</code></li><li style="border: 0px; border-collapse: collapse; border-spacing: 0px; list-style-position: initial; list-style-image: initial; list-style-type: revert; margin-top: revert; margin-right: revert; margin-bottom: 8px; margin-left: revert; padding: revert;">集計は を使って月ごとにまとめられる<code style="border: 1px solid rgb(221, 221, 221); border-radius: 4px; padding: 1px 4px; background: rgb(255, 255, 255); font: 14px / 20px monospace;">GroupBy</code></li></ul></li></ul><pre data-priority="2" style="color: rgb(17, 17, 17); font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(249, 249, 249); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;"><code style="border: 1px solid rgb(221, 221, 221); border-radius: 8px; padding: 12px 20px; background: rgb(255, 255, 255); font: 14px / 20px monospace; display: block; white-space: pre-wrap; margin-right: 20px;"><span style="color: rgb(215, 58, 73);">using</span> Microsoft.EntityFrameworkCore; <span style="color: rgb(215, 58, 73);">using</span> System.Security.Claims; <span style="color: rgb(215, 58, 73);">public</span> IActionResult <span style="color: rgb(111, 66, 193);">Payments</span>(<span style="color: rgb(227, 98, 9);">int</span> year, <span style="color: rgb(227, 98, 9);">int</span> month, <span style="color: rgb(227, 98, 9);">int</span> page = <span style="color: rgb(0, 92, 197);">1</span>, <span style="color: rgb(227, 98, 9);">int</span> pageSize = <span style="color: rgb(0, 92, 197);">20</span>) { <span style="color: rgb(215, 58, 73);">var</span> userId = User.FindFirstValue(ClaimTypes.NameIdentifier); <span style="color: rgb(215, 58, 73);">if</span> (<span style="color: rgb(227, 98, 9);">string</span>.IsNullOrEmpty(userId)) { <span style="color: rgb(215, 58, 73);">return</span> RedirectToAction(<span style="color: rgb(3, 47, 98);">"Login"</span>, <span style="color: rgb(3, 47, 98);">"Account"</span>); } <span style="color: rgb(106, 115, 125);">// 月初と月末を計算</span> <span style="color: rgb(215, 58, 73);">var</span> firstDayOfMonth = <span style="color: rgb(215, 58, 73);">new</span> DateTime(year, month, <span style="color: rgb(0, 92, 197);">1</span>); <span style="color: rgb(215, 58, 73);">var</span> lastDayOfMonth = firstDayOfMonth.AddMonths(<span style="color: rgb(0, 92, 197);">1</span>).AddDays(<span style="color: rgb(0, 92, 197);">-1</span>); <span style="color: rgb(106, 115, 125);">// ベースクエリ(IQueryable)</span> <span style="color: rgb(215, 58, 73);">var</span> query = _context.Payment .Include(p => p.SubjectName) .Where(p => p.UserId == userId) <span style="color: rgb(106, 115, 125);">// ユーザーIDでフィルタ</span> .Where(p => p.Posted >= firstDayOfMonth && p.Posted <= lastDayOfMonth) .OrderBy(p => p.Posted) <span style="color: rgb(106, 115, 125);">// 並び順</span> <span style="color: rgb(106, 115, 125);">// IQueryableなのでまだDBにアクセスしない</span> ; <span style="color: rgb(106, 115, 125);">// ページング</span> <span style="color: rgb(215, 58, 73);">var</span> totalCount = query.Count(); <span style="color: rgb(215, 58, 73);">var</span> payments = query .Skip((page - <span style="color: rgb(0, 92, 197);">1</span>) * pageSize) .Take(pageSize) .ToList(); <span style="color: rgb(106, 115, 125);">// 月別集計例(合計金額)</span> <span style="color: rgb(215, 58, 73);">var</span> monthlySummary = _context.Payment .Where(p => p.UserId == userId) .GroupBy(p => <span style="color: rgb(215, 58, 73);">new</span> { p.Posted.Year, p.Posted.Month }) .Select(g => <span style="color: rgb(215, 58, 73);">new</span> { Year = g.Key.Year, Month = g.Key.Month, TotalAmount = g.Sum(x => x.Amount) }) .OrderByDescending(x => x.Year) .ThenByDescending(x => x.Month) .ToList(); <span style="color: rgb(106, 115, 125);">// ViewModelにまとめて返す</span> <span style="color: rgb(215, 58, 73);">var</span> model = <span style="color: rgb(215, 58, 73);">new</span> PaymentsViewModel { Payments = payments, TotalCount = totalCount, Page = page, PageSize = pageSize, MonthlySummary = monthlySummary }; <span style="color: rgb(215, 58, 73);">return</span> View(model); } <span style="color: rgb(106, 115, 125);">// ViewModel例</span> <span style="color: rgb(215, 58, 73);">public</span> <span style="color: rgb(215, 58, 73);">class</span> <span style="color: rgb(111, 66, 193);">PaymentsViewModel</span> { <span style="color: rgb(215, 58, 73);">public</span> List<Payment> Payments { <span style="color: rgb(215, 58, 73);">get</span>; <span style="color: rgb(215, 58, 73);">set</span>; } <span style="color: rgb(215, 58, 73);">public</span> <span style="color: rgb(227, 98, 9);">int</span> TotalCount { <span style="color: rgb(215, 58, 73);">get</span>; <span style="color: rgb(215, 58, 73);">set</span>; } <span style="color: rgb(215, 58, 73);">public</span> <span style="color: rgb(227, 98, 9);">int</span> Page { <span style="color: rgb(215, 58, 73);">get</span>; <span style="color: rgb(215, 58, 73);">set</span>; } <span style="color: rgb(215, 58, 73);">public</span> <span style="color: rgb(227, 98, 9);">int</span> PageSize { <span style="color: rgb(215, 58, 73);">get</span>; <span style="color: rgb(215, 58, 73);">set</span>; } <span style="color: rgb(215, 58, 73);">public</span> List<<span style="color: rgb(227, 98, 9);">object</span>> MonthlySummary { <span style="color: rgb(215, 58, 73);">get</span>; <span style="color: rgb(215, 58, 73);">set</span>; } } </code></pre><h3 style="border: 0px; border-collapse: collapse; border-spacing: 0px; list-style-position: initial; list-style-image: initial; list-style-type: revert; margin: revert; padding: revert; display: inline-block; font: 18px / 22px Roboto, sans-serif; color: rgb(17, 17, 17); letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgb(249, 249, 249); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">このリファクタリングのメリット</h3><ol style="border: 0px; border-collapse: collapse; border-spacing: 0px; list-style-position: initial; list-style-image: initial; list-style-type: revert; margin: revert; padding: revert; color: rgb(17, 17, 17); font-family: Roboto, Helvetica, sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgb(249, 249, 249); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;"><li style="border: 0px; border-collapse: collapse; border-spacing: 0px; list-style-position: initial; list-style-image: initial; list-style-type: revert; margin-top: revert; margin-right: revert; margin-bottom: 8px; margin-left: revert; padding: revert;"><strong style="font-weight: 700;">UserId フィルタが共通化</strong>され、どの集計やページングにも適用される</li><li style="border: 0px; border-collapse: collapse; border-spacing: 0px; list-style-position: initial; list-style-image: initial; list-style-type: revert; margin-top: revert; margin-right: revert; margin-bottom: 8px; margin-left: revert; padding: revert;"><strong style="font-weight: 700;">IQueryable</strong> を使うことで、必要な条件を後から追加可能</li><li style="border: 0px; border-collapse: collapse; border-spacing: 0px; list-style-position: initial; list-style-image: initial; list-style-type: revert; margin-top: revert; margin-right: revert; margin-bottom: 8px; margin-left: revert; padding: revert;">ページング ( / ) と集計 () を分離して管理できる<code style="border: 1px solid rgb(221, 221, 221); border-radius: 4px; padding: 1px 4px; background: rgb(255, 255, 255); font: 14px / 20px monospace;">Skip</code><code style="border: 1px solid rgb(221, 221, 221); border-radius: 4px; padding: 1px 4px; background: rgb(255, 255, 255); font: 14px / 20px monospace;">Take</code><code style="border: 1px solid rgb(221, 221, 221); border-radius: 4px; padding: 1px 4px; background: rgb(255, 255, 255); font: 14px / 20px monospace;">GroupBy</code></li><li style="border: 0px; border-collapse: collapse; border-spacing: 0px; list-style-position: initial; list-style-image: initial; list-style-type: revert; margin-top: revert; margin-right: revert; margin-bottom: 8px; margin-left: revert; padding: revert;">大量データでも効率的に動作(SQL に変換されて DB 側で処理)</li></ol><p style="border: 0px; border-collapse: collapse; border-spacing: 0px; list-style-position: initial; list-style-image: initial; list-style-type: revert; margin: revert; padding: revert; -webkit-line-clamp: revert; color: rgb(17, 17, 17); font-family: Roboto, Helvetica, sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgb(249, 249, 249); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">もし希望があれば、このコードを <strong style="font-weight: 700;">月別集計とページングを同時に行う API 形式</strong> にもできます。<br>そうすれば SPA やフロントエンドからの非同期呼び出しにも対応できます。</p><p style="border: 0px; border-collapse: collapse; border-spacing: 0px; list-style-position: initial; list-style-image: initial; list-style-type: revert; margin: revert; padding: revert; -webkit-line-clamp: revert; color: rgb(17, 17, 17); font-family: Roboto, Helvetica, sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgb(249, 249, 249); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">この後、私が提案するのは <strong style="font-weight: 700;">「共通フィルタを適用する拡張メソッド化」</strong> です。<br>そうすると、どのコントローラでも のように書けます。<br>これを作りますか?<code style="border: 1px solid rgb(221, 221, 221); border-radius: 4px; padding: 1px 4px; background: rgb(255, 255, 255); font: 14px / 20px monospace;">query.FilterByUser(userId)</code></p><p data-f-id="pbf" style="text-align: center; font-size: 14px; margin-top: 30px; opacity: 0.65; font-family: sans-serif;">Powered by <a href="https://www.froala.com/wysiwyg-editor?pb=1" title="Froala Editor">Froala Editor</a></p>
コピーする
添付画像
画像を変更
Back to List
//検索文:Editor内でHTMLコードをコピーさせる