🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
.NET Core

.NET Coreは、マネージソフトウェアフレームワークでオープンソースで実装されています。クロスプラットフォームを前提に考えられており、Windows/Mac/Linuxで動くアプリケーションを作成することが可能です。

ASP.NET

ASP.NETは動的なWebサイトやWebアプリケーション、そしてWebサービスを構築出来るようにする為、Microsoftによって開発されたウェブアプリケーション開発フレームワークです。

Q&A

解決済

1回答

2917閲覧

ASP.NET Core MVCのViewModelにおいて、元となっているModelのみを参照しているViewが表示できない

K-actus

総合スコア22

.NET Core

.NET Coreは、マネージソフトウェアフレームワークでオープンソースで実装されています。クロスプラットフォームを前提に考えられており、Windows/Mac/Linuxで動くアプリケーションを作成することが可能です。

ASP.NET

ASP.NETは動的なWebサイトやWebアプリケーション、そしてWebサービスを構築出来るようにする為、Microsoftによって開発されたウェブアプリケーション開発フレームワークです。

0グッド

0クリップ

投稿2020/11/24 06:39

編集2020/11/24 08:29

こんにちは。
初質問なので拙いところがあるかと思いますがよろしくお願いします。

Windows10 ASP.NET Core 2.2において、元々ModelとViewが1対1対応でページを作成していたのですが、ViewModelを用いて複数のModelを1つのViewに表示出来るページを作成すると、元となっている複数のModelのうちの1つのみを参照するページが表示出来なくなりました。
何故そうなったのか理由も含めて教えていただけると助かります。
言語はC#です。

ソースコード

以下コード例です。

Models

1using System; 2using System.Collections.Generic; 3using System.Linq; 4using System.Threading.Tasks; 5using System.ComponentModel; 6 7namespace DBAccessSample.Models 8{ 9 public class hogeList 10 { 11 public int Id { get; set; } 12 13 public string hoge { get; set; } 14 15    //ここでは省略しますが本当はプロパティが更に存在します。 16 } 17} 18

Models

1using System; 2using System.Collections.Generic; 3using System.Linq; 4using System.Threading.Tasks; 5using System.ComponentModel; 6 7namespace DBAccessSample.Models 8{ 9 public class hogehogeList 10 { 11 public int Id { get; set; } 12 13 public string hogehoge { get; set; } 14      15    //ここでは省略しますが本当はプロパティが更に存在します。 16 17 } 18}

ViewModels

1using System; 2using System.Collections.Generic; 3using System.Linq; 4using System.Threading.Tasks; 5 6 7namespace DBAccessSample.Models 8{ 9 public class HogeViewModel 10 11 { 12 public int Id { get; set; } //主キー必要? 13 public IEnumerable<hogeList> hogeLists { get; set; } 14 public IEnumerable<hogehogeList> hogeLists { get; set; } 15 } 16}

Controller

1using System; 2using System.Collections.Generic; 3using System.Linq; 4using System.Threading.Tasks; 5using Microsoft.AspNetCore.Mvc; 6using Microsoft.EntityFrameworkCore; 7using DBAccessSample.Data; 8using DBAccessSample.Models; 9 10namespace DBAccessSample.Controllers 11{ 12 public class HogeViewModelController : Controller 13 { 14 15 public IActionResult Index() 16 { 17 HogeViewModel myView = new HogeViewModel(); 18 myView.hogeLists = GethogeLists(); 19 myView.hogehogeLists = GethogehogeLists(); 20 return View(myView); 21 } 22 23 private List<hogeList> GethogeLists() 24 { 25 List<hogeList> hogeLists = new List<hogeList>(); 26 return hogeLists; 27 } 28 29 private List<hogehogeList> GethogehogeLists() 30 { 31 List<hogehogeList> hogehogeLists = new List<hogehogeList>(); 32 return hogehogeLists; 33 } 34 } 35} 36

hogeListのView及びControllerはScaffoldingで作成しました。

Controller

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 DBAccessSample.Data; 9using DBAccessSample.Models; 10 11namespace DBAccessSample.Controllers 12{ 13 public class hogeListsController : Controller 14 { 15 private readonly MyDbContext _context; 16 17 public hogeListsController(MyDbContext context) 18 { 19 _context = context; 20 } 21 22 // GET: hogeLists 23 public async Task<IActionResult> Index() 24 { 25 return View(await _context.hogeLists.ToListAsync()); 26 } 27 28 // GET: hogeLists/Details/5 29 public async Task<IActionResult> Details(int? id) 30 { 31 if (id == null) 32 { 33 return NotFound(); 34 } 35 36 var hogeList = await _context.hogeLists 37 .FirstOrDefaultAsync(m => m.Id == id); 38 if (hogeList == null) 39 { 40 return NotFound(); 41 } 42 43 return View(hogeList); 44 } 45 46 // GET: hogeLists/Create 47 public IActionResult Create() 48 { 49 return View(); 50 } 51 52 // POST: hogeLists/Create 53 // To protect from overposting attacks, please enable the specific properties you want to bind to, for 54 // more details see http://go.microsoft.com/fwlink/?LinkId=317598. 55 [HttpPost] 56 [ValidateAntiForgeryToken] 57 public async Task<IActionResult> Create([Bind("Id, hoge")] hogeList hogeList) 58 { 59 if (ModelState.IsValid) 60 { 61 _context.Add(hogeList); 62 await _context.SaveChangesAsync(); 63 return RedirectToAction(nameof(Index)); 64 } 65 return View(hogeList); 66 } 67 68 // GET: hogeLists/Edit/5 69 public async Task<IActionResult> Edit(int? id) 70 { 71 if (id == null) 72 { 73 return NotFound(); 74 } 75 76 var hogeList = await _context.hogeLists.FindAsync(id); 77 if (hogeList == null) 78 { 79 return NotFound(); 80 } 81 return View(hogeList); 82 } 83 84 // POST: hogeLists/Edit/5 85 // To protect from overposting attacks, please enable the specific properties you want to bind to, for 86 // more details see http://go.microsoft.com/fwlink/?LinkId=317598. 87 [HttpPost] 88 [ValidateAntiForgeryToken] 89 public async Task<IActionResult> Edit(int id, [Bind("Id, hoge")] hogeList hogeList) 90 { 91 if (id != hogeList.Id) 92 { 93 return NotFound(); 94 } 95 96 if (ModelState.IsValid) 97 { 98 try 99 { 100 _context.Update(hogeList); 101 await _context.SaveChangesAsync(); 102 } 103 catch (DbUpdateConcurrencyException) 104 { 105 if (!hogeListExists(hogeList.Id)) 106 { 107 return NotFound(); 108 } 109 else 110 { 111 throw; 112 } 113 } 114 return RedirectToAction(nameof(Index)); 115 } 116 return View(hogeList); 117 } 118 119 // GET: hogeLists/Delete/5 120 public async Task<IActionResult> Delete(int? id) 121 { 122 if (id == null) 123 { 124 return NotFound(); 125 } 126 127 var hogeList = await _context.hogeLists 128 .FirstOrDefaultAsync(m => m.Id == id); 129 if (hogeList == null) 130 { 131 return NotFound(); 132 } 133 134 return View(hogeList); 135 } 136 137 // POST: hogeLists/Delete/5 138 [HttpPost, ActionName("Delete")] 139 [ValidateAntiForgeryToken] 140 public async Task<IActionResult> DeleteConfirmed(int id) 141 { 142 var hogeList = await _context.hogeLists.FindAsync(id); 143 _context.hogeLists.Remove(hogeList); 144 await _context.SaveChangesAsync(); 145 return RedirectToAction(nameof(Index)); 146 } 147 148 private bool hogeListExists(int id) 149 { 150 return _context.hogeLists.Any(e => e.Id == id); 151 } 152 153 ///////////////////////////////////////////////// 154 155 156 157 } 158} 159

###エラー内容
今回の例だとHogeViewModelのページは正しく表示されますが、hogeListだけを表示するページでエラーが出ます。
hogeList単体だとViewModelの継承元というだけで直接は関わっていないと考えていますが、
SqlException: Invalid column name 'FuncMainViewModelId'.
と出て、ViewModelのIdについて言及されます。
しかしViewModelのIdを消すと
InvalidOperationException: The entity type 'HogeViewModel' requires a primary key to be defined.
というエラーが出ます。

そもそもViewModelに主キーは必要なのですか?(参考URLのQiitaの記事だと主キーは書いていません。ASP.NET Coreじゃないからというのもあると思いますが・・・。)

また、ASP.NET CoreのViewModelはScaffoldingでControllerやViewを自動作成することは出来ますか?

よろしくお願いします。

参考URL

https://teratail.com/questions/74013
http://kuttsun.blogspot.com/2018/03/mvc-viewmodel.html
https://qiita.com/KktkiY/items/f28528916e97310262e0

補足情報(FW/ツールのバージョンなど)

Visual Studio 2017 Community
Microsoft.AspNetCore.All 2.2.8
Windows10 Pro 1909

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2020/11/24 06:42

ASP.NET のタグをつけて下さい。 参考 url はリンクを張ってください。
退会済みユーザー

退会済みユーザー

2020/11/24 10:11 編集

> SqlException: Invalid column name 'FuncMainViewModelId'. SqlException が出るコードは質問には全く見当たりません。質問に書いてないことは閲覧者、回答者には分かりません。分かるように十分な情報を書いてください。
K-actus

2020/11/24 08:30

タグ、リンクの修正及びソースコードの追加を行いました。
退会済みユーザー

退会済みユーザー

2020/11/24 10:11 編集

話が通じないようですね。 スキャフォールディング機能で追加した hogeListsController のコードを追記したようですが、それは期待通り動くのですよね。 動かないのは HogeViewModelController の方ではないのですか? それには SqlException が出るコードは見当たりません。だから、何か質問に書いてないことがあるのではないのですかと言ったのです。
退会済みユーザー

退会済みユーザー

2020/11/25 01:43 編集

質問の意味を誤解していたようです。動かないのは HogeViewModelController ということではなかったのですね。 質問に書かれている HogeViewModelController と HogeViewModel、それに View を定義したら、元々動いていた hogeListsController が動かなくなり、SqlException とか InvalidOperationException がスローされるということだと理解しました。(理解が違っていたらその旨コメントください) 上にも書きましたが、HogeViewModelController にも、それが使う HogeViewModel にも SqlException が出るコードは見当たりません。InvalidOperationException も "requires a primary key" というエラーメッセージですので、出るはずのないものです。 それらの例外は Entity Framework, SQL Server に関係するもので、質問に書かれている HogeViewModelController と HogeViewModel はそれらとはどう見ても関係ないです。 なので、何か質問に書いてないことがあるのではないのですか?・・・と言う疑問は変わってないので。その疑問に答えてもらえない限りこの質問には答えようがないです。
guest

回答1

0

ベストアンサー

質問に書かれている HogeViewModelController と HogeViewModel、加えて Index アクションメソッドに対応する View を定義したら、元々動いていた hogeListsController が動かなくなり、SqlException または InvalidOperationException がスローされるということだと理解してレスします。(理解が違っていたらその旨回答のコメント欄に書いてください)

質問のコメント欄にも書きましたが、質問に書いてある HogeViewModelController にも HogeViewModel にも SqlException という SQL Server に関係するような例外がスローされるようなコードはありません。

InvalidOperationException の方も "requires a primary key" というエラーメッセージですので SQL Server 関係の例外のようで、質問のコードを見る限り HogeViewModelController と HogeViewModel とは全く関係がないものです。

なのに、 hogeListsController が動かなくなり、SqlException とか InvalidOperationException がスローされるということは、質問に書いてない何かがあるとしか考えられません。

元の hogeListsController が関係する Entity Framework 関係のコードに手を加えたとか、質問のコードには無いが実は HogeViewModelController か HogeViewModel に既存の Entity Framework や SQL Server に影響を与えるコードがあるとか。

なので、質問の「ASP.NET Core MVCのViewModelにおいて、元となっているModelのみを参照しているViewが表示できない」が何故かとその解決策は、上の疑問に答えてさらなる情報を提供してもらえないと答えようがないです。(この回答の一番最後の方に想像を書きましたが、違うかも)

というわけで、以下の質問にだけ回答しておきます。

複数のModelを1つのViewに表示出来るページを作成する
そもそもViewModelに主キーは必要なのですか?
ASP.NET CoreのViewModelはScaffoldingでControllerやViewを自動作成することは出来ますか?

上記のことが分かれば後は自助努力で SqlException または InvalidOperationException がスローされるという問題を解決できるかもしれませんので。

複数のModelを1つのViewに表示出来るページを作成する

SQL Server に hogeList, hogehogeList という 2 つのテーブルがあって、それらからデータを取得してビューに渡して表示したいということと想像してます。

実際は、GethogeLists メソッド、GethogehogeLists メソッドは、それぞれ _context.hogeLists.ToList(), _context.hogehogeList.ToList() などの Entity Framework を使って、SQL Server のレコードを IEnumerable<hogeList>, IEnumerable<hogehogeList> というオブジェクトとして取得しているのであろうと想像してます。

そして、コントローラーでそれらを HogeViewModel というモデルに格納し、ビューに渡して表示するのですよね。であれば、基本的には質問のコードで合ってます。

それだけであれば SqlException または InvalidOperationException がスローされるということはあり得ません。

そもそもViewModelに主キーは必要なのですか?

不要です。ビューで何らかのために使うということはら話は別ですが。それの有無はエラーには全く関係ないはずです。それによって影響があるということは、質問に書いてない何かがある以外には考えられません。

ViewModel とか言うと何か特別なものと思っているかもしれませんが、要するに MVC の M すなわちモデルです。以下の記事を見てください。

ASP.NET MVC の Model
http://surferonwww.info/BlogEngine/post/2020/05/29/model-in-aspnet-mvc.aspx

ビューにデータを渡す目的で使われるものをビューモデルと呼ぶことがあります。そこに主キー云々の話は出てきません。

ASP.NET CoreのViewModelはScaffoldingでControllerやViewを自動作成することは出来ますか?

それをやって失敗したのが今の状況ではないかと疑っています

コンテキストクラスに Visual Studio が勝手に public DbSet<HogeViewModel> HogeViewModel { get; set; } とかを作ってませんか? であれば、それが問題の原因だと思います。

今回のような HogeViewModel のような場合は、基本的に、スキャフォールディング機能を使ってのコントローラー/ビューの自動生成は出来ないので、空のコントローラー/ビューを作ってそれに自力でコードを書いて実装してください。

投稿2020/11/25 05:00

編集2020/11/25 05:17
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

K-actus

2020/11/25 08:18

仰る通りコンテキストクラスが原因でした。 非常に丁寧でわかりやすい回答、ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問