こんにちは。
ASP.NET Coreについて初学者なので拙いところもあると思いますが、よろしくお願いします。
実現したいこと
※データベースのテーブルは「テーブル」、HTMLのテーブルについては"Table"とここでは表記します。
例として以下のようなModelのテーブルを想定します。
ID | 識別子 | 名前 |
---|---|---|
1 | A | りんご |
2 | A | みかん |
3 | B | パンダ |
4 | B | キリン |
5 | A | もも |
6 | C | 日本 |
識別子はString型であり、種類数は決まっていません。
この時、識別子の種類分Tableを作成し、Viewで以下のように表示したいです。
ID | 識別子 | 名前 |
---|---|---|
1 | A | りんご |
2 | A | みかん |
5 | A | もも |
ID | 識別子 | 名前 |
---|---|---|
3 | B | パンダ |
4 | B | キリン |
ID | 識別子 | 名前 |
---|---|---|
6 | C | 日本 |
わからないところ
識別子の数が決まっていないので、単なるSELECTだけでは実現出来ないと考えています。
今のところ、元のModelからデータを全て取ってきてForなりで識別子の種類数を算出し、その分ViewでTableを作成して割り振るといった処理を考えています。
しかしそれを実装するにしてもその処理をどこに記述するべきなのか(Controller? View?)わかっていません。
View側(cshtmlかjavascript)でデータの編集をしても良いのでしょうか?
それともModelに関することはController側で処理するのが好ましいですか?
またもっとスマートなやり方があればそうしたいです。
また、テーブルを分けるという方針は無しでお願いします。
よろしくお願いします。
補足情報
Visual Studio 2017 Community
Microsoft.AspNetCore.All 2.2.8
Windows10 Pro 1909
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/11/30 07:36
退会済みユーザー
2020/11/30 07:42 編集
2020/11/30 07:50
退会済みユーザー
2020/11/30 08:18
退会済みユーザー
2020/11/30 22:44
退会済みユーザー
2020/12/01 04:45
2020/12/01 09:24
退会済みユーザー
2020/12/01 12:07
回答2件
0
ベストアンサー
識別子の数が決まっていないので、単なるSELECTだけでは実現出来ないと考えています。
今のところ、元のModelからデータを全て取ってきてForなりで識別子の種類数を算出し、その分ViewでTableを作成して割り振るといった処理を考えています。
LINQ to Entitiesの Queryable.GroupBy メソッドを使ってください。
Entity Frameworkを使用してデータベースからEntityのコレクションを取得できるように環境を整える必要があります。
※接続するプロバイダーによってはGroupByがSQL等の命令に変換できず、Client side GroupBy is not supported 等のエラーが出るため、その場合はEntityのコレクションを取得し、ToListメソッド等でIEnumerableに変換した上でLINQ to EntitiesではなくLINQ to ObjectsのGroupByを使ってください。
しかしそれを実装するにしてもその処理をどこに記述するべきなのか(Controller? View?)わかっていません。
View側(cshtmlかjavascript)でデータの編集をしても良いのでしょうか?
それともModelに関することはController側で処理するのが好ましいですか?
データの整形はViewでは行わないと思います。
となると、その選択肢の中ではControllerクラスに書くことになりますが、クリーンアーキテクチャのようなソフトウェアアーキテクチャを取り入れている場合はその限りではありません。
またもっとスマートなやり方があればそうしたいです。
率直に思いつくやり方は、EFとGroupByを使用した方法になります。
Controller
- データベースからEntity Frameworkを使用してEntityのコレクションを取得
- Controllerで識別子をキーにコレクションをGroupByし、その結果
IEnumerable<IGrouping<TKey,TElement>>
)をViewに渡す
View
- Razor構文を使用してforeachで各グループ毎にtableタグを使い表を作る
- それぞれのtableタグでグループが持つ各要素毎にtr,thタグなどで行を追加&行にデータを書き込む
Sample
EFからスキャフォールディングで生成したControllerをベースに、Indexメソッドだけ弄ってます。
C#
1using System; 2using System.Collections.Generic; 3using System.Linq; 4using System.Threading.Tasks; 5using Microsoft.AspNetCore.Mvc; 6using Microsoft.AspNetCore.Mvc.Rendering; 7using Microsoft.EntityFrameworkCore; 8using WebApplication3.Models; 9 10namespace WebApplication3.Controllers 11{ 12 public class SampleController : Controller 13 { 14 private readonly SampleContext _context; 15 16 public SampleController(SampleContext context) 17 { 18 _context = context; 19 } 20 21 // GET: Sample 22 public async Task<IActionResult> Index() 23 { 24 return View(await _context.SampleDataModels.GroupBy(x => x.Identifier).ToListAsync()); 25 } 26 27 // GET: Sample/Details/5 28 public async Task<IActionResult> Details(int? id) 29 { 30 if (id == null) 31 { 32 return NotFound(); 33 } 34 35 var sampleDataModel = await _context.SampleDataModels 36 .FirstOrDefaultAsync(m => m.Id == id); 37 if (sampleDataModel == null) 38 { 39 return NotFound(); 40 } 41 42 return View(sampleDataModel); 43 } 44 45 // GET: Sample/Create 46 public IActionResult Create() 47 { 48 return View(); 49 } 50 51 // POST: Sample/Create 52 // To protect from overposting attacks, please enable the specific properties you want to bind to, for 53 // more details see http://go.microsoft.com/fwlink/?LinkId=317598. 54 [HttpPost] 55 [ValidateAntiForgeryToken] 56 public async Task<IActionResult> Create([Bind("Id,Identifier,Name")] SampleDataModel sampleDataModel) 57 { 58 if (ModelState.IsValid) 59 { 60 _context.Add(sampleDataModel); 61 await _context.SaveChangesAsync(); 62 return RedirectToAction(nameof(Index)); 63 } 64 return View(sampleDataModel); 65 } 66 67 // GET: Sample/Edit/5 68 public async Task<IActionResult> Edit(int? id) 69 { 70 if (id == null) 71 { 72 return NotFound(); 73 } 74 75 var sampleDataModel = await _context.SampleDataModels.FindAsync(id); 76 if (sampleDataModel == null) 77 { 78 return NotFound(); 79 } 80 return View(sampleDataModel); 81 } 82 83 // POST: Sample/Edit/5 84 // To protect from overposting attacks, please enable the specific properties you want to bind to, for 85 // more details see http://go.microsoft.com/fwlink/?LinkId=317598. 86 [HttpPost] 87 [ValidateAntiForgeryToken] 88 public async Task<IActionResult> Edit(int id, [Bind("Id,Identifier,Name")] SampleDataModel sampleDataModel) 89 { 90 if (id != sampleDataModel.Id) 91 { 92 return NotFound(); 93 } 94 95 if (ModelState.IsValid) 96 { 97 try 98 { 99 _context.Update(sampleDataModel); 100 await _context.SaveChangesAsync(); 101 } 102 catch (DbUpdateConcurrencyException) 103 { 104 if (!SampleDataModelExists(sampleDataModel.Id)) 105 { 106 return NotFound(); 107 } 108 else 109 { 110 throw; 111 } 112 } 113 return RedirectToAction(nameof(Index)); 114 } 115 return View(sampleDataModel); 116 } 117 118 // GET: Sample/Delete/5 119 public async Task<IActionResult> Delete(int? id) 120 { 121 if (id == null) 122 { 123 return NotFound(); 124 } 125 126 var sampleDataModel = await _context.SampleDataModels 127 .FirstOrDefaultAsync(m => m.Id == id); 128 if (sampleDataModel == null) 129 { 130 return NotFound(); 131 } 132 133 return View(sampleDataModel); 134 } 135 136 // POST: Sample/Delete/5 137 [HttpPost, ActionName("Delete")] 138 [ValidateAntiForgeryToken] 139 public async Task<IActionResult> DeleteConfirmed(int id) 140 { 141 var sampleDataModel = await _context.SampleDataModels.FindAsync(id); 142 _context.SampleDataModels.Remove(sampleDataModel); 143 await _context.SaveChangesAsync(); 144 return RedirectToAction(nameof(Index)); 145 } 146 147 private bool SampleDataModelExists(int id) 148 { 149 return _context.SampleDataModels.Any(e => e.Id == id); 150 } 151 } 152}
cshtml
1@model IEnumerable<IGrouping<string,WebApplication3.Models.SampleDataModel>> 2 3@{ 4 ViewData["Title"] = "Index"; 5} 6 7<h2>Index</h2> 8 9<p> 10 <a asp-action="Create">Create New</a> 11</p> 12 13@foreach (var group in Model) 14{ 15 <table class="table"> 16 <thead> 17 <tr> 18 <th> 19 @Html.DisplayNameFor(model => model.First().Identifier) 20 </th> 21 <th> 22 @Html.DisplayNameFor(model => model.First().Name) 23 </th> 24 <th></th> 25 </tr> 26 </thead> 27 <tbody> 28 @foreach (var item in group) 29 { 30 <tr> 31 <td> 32 @Html.DisplayFor(modelItem => item.Identifier) 33 </td> 34 <td> 35 @Html.DisplayFor(modelItem => item.Name) 36 </td> 37 <td> 38 <a asp-action="Edit" asp-route-id="@item.Id">Edit</a> | 39 <a asp-action="Details" asp-route-id="@item.Id">Details</a> | 40 <a asp-action="Delete" asp-route-id="@item.Id">Delete</a> 41 </td> 42 </tr> 43 } 44 </tbody> 45 </table> 46}
投稿2020/12/02 07:15
編集2020/12/03 06:49総合スコア2663
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
退会済みユーザー
2020/12/03 00:14
2020/12/03 01:09
2020/12/03 06:12 編集
2020/12/03 05:39
退会済みユーザー
2020/12/03 05:58
2020/12/03 06:02 編集
退会済みユーザー
2020/12/03 06:17
2020/12/03 06:44 編集
退会済みユーザー
2020/12/03 06:59
2020/12/03 08:07
0
質問のコメント欄で、
あなたがどこまで自分で実装できたか、どこで躓いていて、何が分かれば解決できるかもう少し具体的に質問欄に書いてください。
・・・とお願いしたのですが、返事がないということは多分手も足も出ないのであろうと想像して、[識別子] 別に複数の Table を表示する方法の案・ヒントを書いておきます。
Entitiy Framework とコンテキストクラス、エンティティクラスを使って DB からデータを取得していると想像してますが(それすら質問には書いてない情報不足ということを認識してください)、であれば List<List<T>> オブジェクト(T はエンティティクラス。[識別子] の数だけ List<T> を含む)を Controller で作って、それを View に渡し、View では foreach ループを回して [識別子] 別に Table を作成するようにしてはどうですか?
言葉では分かり難いと思いますので Controller のアクションメソッドのサンプルを書いておきます。エンティティクラス名は Products、[識別子] は Identifier に読み替えてください。 List<List<Products>> を作って View に渡します。
public async Task<IActionResult> ListByIdentifier() { List<Products> productList = await _context.Products.ToListAsync(); string[] identifiers = productList.Select(p => p.Identifier).Distinct().ToArray(); List<List<Products>> model = new List<List<Products>>(); foreach (string id in identifiers) { List<Products> productByIdentifier = productList.Where(p => p.Identifier == id).ToList(); model.Add(productByIdentifier); } return View(model); }
注:動かして検証などはしてない(DB がないとできない)頭の中で考えただけのサンプルです。質問者さんのケースでどのようにできるかは自分で考えてください。
【追記】
Microsoft が提供するサンプルデータベース Northwind の Products テーブルを使って、上に書いた案でできることを確認したのでその内容を書いておきます。
Northwind の Products テーブル
SupplierID が質問者さんの [識別子] と思ってください。int 型で NULL 可になってますが、それは本質的なところとは関係ないはずです。
Model (エンティティクラス)
View
Controller / Action Method
結果 (ブラウザの表示)
投稿2020/12/02 06:18
編集2020/12/02 08:48退会済みユーザー
総合スコア0
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。