質問をすることでしか得られない、回答やアドバイスがある。

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

新規登録して質問してみよう
ただいま回答率
85.50%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

MVC

MVC(Model View Controller)は、オブジェクト指向プログラミングにおけるモデル・ビュー・コントローラーの総称であり、ソフトフェア開発で使われている構築パターンとしても呼ばれます。

Razor

RazorはASP.NET Web PagesとASP.NET MVCで使われているビュー・エンジンです。HTMLマークアップとC#またはVisual Basicのコードに対応しています。マークアップとコードの間の切り替えは"@"で記されています。

ASP.NET

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

Q&A

解決済

2回答

1803閲覧

スキャフォールディングで生成された値の表示形式を変更したい

pomu.pomupomu

総合スコア18

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

MVC

MVC(Model View Controller)は、オブジェクト指向プログラミングにおけるモデル・ビュー・コントローラーの総称であり、ソフトフェア開発で使われている構築パターンとしても呼ばれます。

Razor

RazorはASP.NET Web PagesとASP.NET MVCで使われているビュー・エンジンです。HTMLマークアップとC#またはVisual Basicのコードに対応しています。マークアップとコードの間の切り替えは"@"で記されています。

ASP.NET

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

0グッド

0クリップ

投稿2018/08/22 12:15

編集2018/09/30 05:25

前提・実現したいこと

ASP.NET MVC5 で掲示板を作成している初学者です。
スレッドでレスを投稿をする際にASP.NET Identityで獲得したユーザーIdやレスを返そうとしているスレッドのIdを初期値として持ったままレスをできるようにしたいと考えましたが、うまくいかないので投稿しました。

(コード添付に当たって、全体を貼った後に自分で書き直したところ等をまとめています)

発生している問題・エラーメッセージ

スキャフォールディングしたままの状態では、次のような見栄えになっています。
イメージ説明
この状態では、誰がレスを書き込むのかを示すResOwneridがデータベース中にある全件がドロップダウンリストで表示されてしまいます。そこで、ResOwnerIdをTextBox等に変更して初期値を現在ログインしているユーザーIdにすることはできないか、と思い投稿しました。

以前、同じような質問をしたのですが、TextBoxに値は入ったもののそのあとsubmitしてもうまくDBに値が反映されなかったため再度投稿しました。
(ちなみに問題解決時に、TextBoxのname属性に問題があったためにバインディングがうまくいかなかったのだろうということが推定できました)
https://teratail.com/questions/135216

現在、上記Urlの教えを取り込み、コードを書きなおしたところ、次のようになりました。
添付画像中のテキストボックスに入っている6aa・・・の文字列はResOwnerIdのEditor欄に初期値として入って欲しいASP.NET Identityで設定したログイン中のUserIdです。
(この時点では、Textboxではモデルを経由してデータベースに書き込むすべはないのであろうと考えていたため、EditorForにこだわっていました。)
イメージ説明

該当のソースコード と 試したこと

ControllerとViewの該当部分を記します。(Modelはどこをはるかわからなかったので指摘あれば貼ります)

Controller(2行目の"int? Id"のIdには、スレタイをクリックした際に渡される、スレッドのIdが含まれる予定です。)

c#

1 // GET: Responses/Create 2 public ActionResult Create(int? Id) 3 { 4 var UserId = User.Identity.GetUserId(); 5 ViewBag.ResOwnerId = UserId; 6 // ViewBag.ResOwnerId = new SelectList(db.AspNetUsers, "Id", "Email"); 7 ViewBag.TopicId = new SelectList(db.Topics, "Id", "Title"); 8 return View(); 9 }

View(SortNoは見やすさと文字数の関係で省略してます)

C#

1 2@using (Html.BeginForm()) 3{ 4 @Html.AntiForgeryToken() 5 6<div class="form-horizontal"> 7 <h4>Responses</h4> 8 <hr /> 9 @Html.ValidationSummary(true, "", new { @class = "text-danger" }) 10 11 <div class="form-group"> 12 @Html.LabelFor(model => model.TopicId, "TopicId", htmlAttributes: new { @class = "control-label col-md-2" }) 13 <div class="col-md-10"> 14 @Html.DropDownList("TopicId", null, htmlAttributes: new { @class = "form-control" }) 15 @Html.ValidationMessageFor(model => model.TopicId, "", new { @class = "text-danger" }) 16 </div> 17 </div> 18 19 20 <div class="form-group"> 21 @Html.LabelFor(model => model.Contents, htmlAttributes: new { @class = "control-label col-md-2" }) 22 <div class="col-md-10"> 23 @Html.EditorFor(model => model.Contents, new { htmlAttributes = new { @class = "form-control" } }) 24 @Html.ValidationMessageFor(model => model.Contents, "", new { @class = "text-danger"}) 25 </div> 26 </div> 27 28 <div class="form-group"> 29 @Html.LabelFor(model => model.ResOwnerId, "ResOwnerId", htmlAttributes: new { @class = "control-label col-md-2" }) 30 <div class="col-md-10"> 31 @Html.EditorFor(model => model.ResOwnerId, new { htmlAttributes = new { @class = "form-control", value = ViewBag.ResOwnerId } }) 32 @Html.ValidationMessageFor(model => model.ResOwnerId, "", new { @class = "text-danger" }) 33 </div> 34 </div> 35 @Html.TextBox("username", (string)ViewBag.ResOwnerId, new { @class = "form-control" }) 36 37 38 <div class="form-group"> 39 <div class="col-md-offset-2 col-md-10"> 40 <input type="submit" value="Create" class="btn btn-default" /> 41 </div> 42 </div> 43</div> 44} 45

以上のうち、Controllerは次のように記すことによって、ResOwnerIdに現在ログイン中のユーザーIdを格納しました。(ViewのTextBoxでユーザーIdを表示できました。)

c#

1 var UserId = User.Identity.GetUserId(); 2 ViewBag.ResOwnerId = UserId;

また、ViewはResOwneridについて、

c#

1 @Html.DropDownList("ResOwnerId", null, htmlAttributes: new { @class = "form-control" })

を次のように修正しました。その結果、EditorForは空欄でvalueとしてResOwnerIdが格納されませんでした。(TextBoxにResOwnerIdは表示されたので、ViewBag.ResOwnerIdに値はControllerから渡されていると考えています。)

C#

1       @Html.EditorFor(model => model.ResOwnerId, new { htmlAttributes = new { @class = "form-control", value = ViewBag.ResOwnerId } })

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

VS2017
Windows7
.Net Framework 4.6.1
MVC5

問題解決がEditorForではなく、TextBoxでも行うことができたため、質問の内容を修正しました。
TextBoxではなくEditorForでも行えるとは思うので、出来次第再度加筆しようとおもいます。

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

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

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

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

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

退会済みユーザー

退会済みユーザー

2018/08/22 22:40

なぜ TextBox を EditorFor に変更したいのですか? TextBox でやりたいことは出来ていたと思うのですが。
退会済みユーザー

退会済みユーザー

2018/08/23 02:43

TextBox を EditorFor にしたい理由は、何かうまくいかないことがあって、EditorFor に代えれば解決すると思っているのではなかろうかと想像していますがどうですか? TextBox では何が問題だと思っているのか、EditorFor に代えることによって何を期待しているのかをきちんと書いてもらわないと、回答しても時間と労力の無駄になるので聞いているのですが。
退会済みユーザー

退会済みユーザー

2018/08/23 02:45 編集

前のスレッドでも言いましたが、スキャフォールディング機能を使って View を自動生成すると DropDownList が表示されたというのは、基になる Model にマズイところがあるからではないかと思います。たぶん、そこを直さないと根本的な問題の解決にはならないと思いますよ。
pomu.pomupomu

2018/08/23 04:07

こんにちは、返信が遅くなってしまい申し訳ありません。TextBoxでは、Create中のsubmitを押した際にデータがモデルを経由してデータベースに反映されないからダメなのではないか、と考えたからです。
pomu.pomupomu

2018/08/23 04:09

つまるところ<input type="submit" value="Create" class="btn btn-default" />をクリックした際にデータベースが更新されればいいと考えています。
pomu.pomupomu

2018/08/23 04:10

基になるモデルを加筆してみます。(あれから考えたのですが、DropDownListにならずに任意の物を最初から表示?させるというのが改善の余地が見つからなかったです・・・すみません)
pomu.pomupomu

2018/08/23 04:26

先に急いで返信を・・・!と思って書いてから、TextBoxでもできるということは、***ForじゃなくてもDBに書けるのか!と気がつきました。やってみたところ、前はできなかったのになぜかできました・・・!指摘ありがとうございました!
退会済みユーザー

退会済みユーザー

2018/08/23 04:38

モデルバインディングということをご存じですか? name 属性が重要ですが、どうなってましたか?
pomu.pomupomu

2018/08/23 05:59

"モデルバインディング"という単語を初めて聞きました。Viewのテキストボックス等で指定したname属性がModelのEntityDataFrameで橋渡しされながらどのデータベースのテーブルの中のカラムと繋がりを持つか示すもの、ということでしょうか。
pomu.pomupomu

2018/08/23 06:04

もし、そうであれば、Viewのテキストボックスで記したResOwnerIdがADO.NETで作成したModelの.edmx拡張子のファイル(最後の追記した画像)ResponsesテーブルのResOwnerIdと名前が同じなのでマッチングし、データベースのResponsesテーブルのResOwnerIdとマッチしてるため、name属性はうまくいってるのではと考えています。
退会済みユーザー

退会済みユーザー

2018/08/23 08:24

コメント欄には書ききれないので回答欄に書きます。
guest

回答2

0

ベストアンサー

(1) DropDownList になってしまう理由

質問にアップされた Entity Data Model の画像を見ての想像ですが(想像と言っても自信度 90% ぐらいはあります)・・・

スキャフォールディング機能で View を自動生成する際に使ったモデル(クラス)は画像の中の Responses ですよね。その中の ResOwnerId から AspNetUsers の Id に外部キーが張られているからです。

そうなっていると、スキャフォールディングで自動的に、アクションメソッドには、前のスレッドに書いてあった、

ViewBag.ResOwnerId = new SelectList(db.AspNetUsers, "Id", "UserName");

というコードが生成され(なぜ自動的に UserName が選ばれるのかは謎ですが)、View には、

@Html.DropDownList("ResOwnerId", null, htmlAttributes: new { @class = "form-control" })

というコードが生成され、結果 DropDownList になるという仕組みになっているようです。

ResOwnerId から AspNetUsers の Id に外部キーを張るのを止めればそのようなことにはならないはずです。と言うか、外部キーなど張るべきではない、張らないで済むように考えるべきと思うのですが。

そもそも、ASP.NET Identity が EF Code First で作る各テーブルと、質問者さんが自分で作ったと思われる Responses 他のテーブルを一緒にして EDM を作るというのは、自分に言わせてもらえれば普通ではないと思います。ましてや外部キーを張るなんて・・・ 考え直した方がよさそうです。

(2) モデルバインディングが上手くいかない理由

最終的に以下のようにしてうまくいったということですが、うまくいかなかったときは "ResOwnerId" が違っていたのではないかと思います。

@Html.TextBox("ResOwnerId", (string)ViewBag.ResOwnerId, new { @class = "form-control", @readonly = "readonly" })

上記が ASP.NET によって html ソースに変換されると以下のようになるはずです。

<input ... name="ResOwnerId" type="text" value="6aa17057-..." />

私がコメントで「name 属性が重要ですが、どうなってましたか?」と言ったのは上の name のことです。

ボタンクリックで上記 input 要素からは ResOwnerId=6aa17057-... という形(左辺が name 属性、右辺が value 属性の値)でテキストボックス入力がサーバーに送信されます。

今回のケースでテキストボックスは複数ありますが、全て同様で <name 属性の値>=<value 属性の値> という形でデータがサーバーに送信されます。

アクションメソッドは Create(Responses responses) のようにしていると思いますが、その引数の responses に、送信されてきた複数の <name 属性の値>=<value 属性の値> というデータから Responses のインスタンスを作って渡すのがモデルバインディングです。

Responses クラスには複数のプロパティ(SortNo, TopivId, Contents, ResOwnerId 他)がありますが、送信されてきた複数の <name 属性の値>=<value 属性の値> というデータから、プロパティ名と同名の <name 属性の値> を探して、その <value 属性の値> をプロパティに代入します。

なので、@Html.TextBox("ResOwnerId" ... の "ResOwnerId" が違っていたらバインドできません。それが最初の状態だったと思います。

(3) TextBox を EditoFor に変更する方法

アクションメソッドで return View(); とするのではなく、var model = new Responses(); で Responses クラスのインスタンスを作り、その ResOwnerId プロパティに値を代入してから return View(model); とすれば EditorFor に値が表示されるはずです。

投稿2018/08/23 08:34

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

pomu.pomupomu

2018/08/23 08:53

(1) ドロップダウンリストになるのが必然なのはそこのせいかな・・・とふわっと思い返していたため、「ひえっ」って声が出たぐらいその通りだと思います。 外部キーを張った理由として「スレッドを投稿する際に誰が投稿したのかわかるようにするにはResOwnerIdは、ユーザー名変更を考慮してResOwnerIdとAspNetUsersテーブルの(ユーザー)Idが常にマッチするものであるべきで、それなら外部キーでくっつけたらいいな?」と考えていました。 が、しかし、Controller側でデータベースからマッチするものを探す際にAspNetUsersテーブルもIncludeし、.where()を加えたら外部キーを張り巡らせなくてもいいのではないか、と思いました。 たしかに、今になって修正して壊れないかは不安ですが、他の手を打った方がいいということ多分理解しました。
pomu.pomupomu

2018/08/23 08:58

(2) 「HTMLタグでのname属性はパッと見ればわかるようになってるけど、Razorってどうやって書いてどうやってどのデータがどこにいくか判断して授受してるの・・・。」という状態だったので、とてもわかりやすい説明とミスの指摘の予想で理解しました。ありがとうございます。
pomu.pomupomu

2018/08/23 09:01

(3) ずっとViewのEditorForに対して Value=ResOwnerId といった記述等をして錯乱してたのでスッキリしました。どこを探しても見つからなかった解決策を教えてくださってありがとうございます・・・! Controller側のアクションにインスタンスと返り値を書くとは思いもしてなかったです。
guest

0

スキャフォールディングした際に生成される次の項目を変更する

c#

1@Html.DropDownList("ResOwnerId", null, htmlAttributes: new { @class = "form-control" })

C#

1 @Html.TextBox("ResOwnerId", (string)ViewBag.ResOwnerId, new { @class = "form-control", @readonly = "readonly" })

投稿2018/08/23 04:43

pomu.pomupomu

総合スコア18

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

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

退会済みユーザー

退会済みユーザー

2018/08/23 05:19

それは質問(TextBox に代えて EditorFor を使にはどうしたらいいか)の回答になってないですよ。質問者さんがそもそもの問題としていたモデルバインディングが上手くいかないことの解決策とは言えるかもしれませんが。 質問する際は、本質的なことを(モデルバインディングが上手くされるようにするにはどうしたらいいか)質問するようにしましょう。 その前に、スキャフォールディングで意に反して DropDownList になってしまうことを解決する(EditorFor になるようにする)のが先だと思いますが。そうすれば、たぶん、今回のような問題に悩むことはなかったと思います。
pomu.pomupomu

2018/08/23 06:10

質問の本質の見極めができなかったばっかりにこのような回答を勝手に書いてまい、申し訳ありません。次からは質問の本質に触れるように投稿できるよう心がけます。 なぜ、ドロップダウンリストの項目とEditorForの項目に分かれているのかというのが正直ふわっとしかわかってないので、そこを調べてみます。(というか、サンプルでも誰かが作ったDBを見たことがないので探して、自分のものと対比してみようとおもいます)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問