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

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

新規登録して質問してみよう
ただいま回答率
85.48%
.NET Core

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

データベース

データベースとは、データの集合体を指します。また、そのデータの集合体の共用を可能にするシステムの意味を含めます

ASP.NET

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

ASP.NET MVC Framework

ASP.NET MVC Frameworkは、MVCパターンをベースとした、マイクロソフトのウェブアプリケーション開発用のフレームワークです。

Q&A

解決済

2回答

2696閲覧

ASP.NET CoreのViewModelで、元のViewとDBを共有したい。

K-actus

総合スコア22

.NET Core

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

データベース

データベースとは、データの集合体を指します。また、そのデータの集合体の共用を可能にするシステムの意味を含めます

ASP.NET

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

ASP.NET MVC Framework

ASP.NET MVC Frameworkは、MVCパターンをベースとした、マイクロソフトのウェブアプリケーション開発用のフレームワークです。

0グッド

0クリップ

投稿2020/12/03 07:44

編集2020/12/04 06:24

こんにちは。
ASP.NET Coreについて初学者なので拙いところもあると思いますが、よろしくお願いします。

実現したいこと

具体例でお話しします。
例えばAnimalとPlantいうModelがあり、それを元にスキャフォールディングしたViewとControllerが存在しているとします。
この時データベースにはDbInitializerで追加した初期データか、実際にブラウザ上でCreateしたデータが入っています。

その後、AnimalとPlantという2つのModelを元にしてLivingViewModelを作成するとします。

C#

1using System; 2using System.Collections.Generic; 3using System.Linq; 4using System.Threading.Tasks; 5 6 7namespace WebApplication.Models 8{ 9 public class LivingViewModel 10 11 { 12 public IEnumerable<Animal> Animals { get; set; } 13 public IEnumerable<Plant> Plants { get; set; } 14 } 15}

このとき、AnimalもしくはPlantのページで追加したデータや初期データをViewModelのページに反映させる、またLivingViewModelの方で編集したデータをAnimalもしくはPlantのページに反映させるControllerの書き方がわかりません。

以下AnimalのControllerです。

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

AnimalやPlantのデータとは関係なくLivingViewModelに初期データを追加することは出来るのですが、相互に作用できるようにしたいです。

以下現在のViewModelのControllerです。

C#

1using System; 2using System.Collections.Generic; 3using System.Linq; 4using System.Threading.Tasks; 5using Microsoft.AspNetCore.Mvc; 6using Microsoft.EntityFrameworkCore; 7using WebApplication.Data; 8using WebApplication.Models; 9 10namespace WebApplication.Controllers 11{ 12 public class LivingViewModelsController : Controller 13 { 14 15 public IActionResult Index() 16 { 17 LivingViewModel myView = new LivingViewModel(); 18 myView.Animals = GetAnimals(); 19 myView.Plants = GetPlants(); 20 return View(myView); 21 } 22 23 private List<Animal> GetAnimals() 24 { 25 List<Animal> Animals = new List<Animal>(); 26 Animals.Add(new Animal { /*初期データ*/ }); 27 return Animals; 28 29 } 30 31 private List<Plant> GetPlants() 32 { 33 List<Plant> Plants = new List<Plant>(); 34 Plants.Add(new Plant { /*初期データ*/ }); 35 36 return Plants; 37 } 38 } 39} 40

DbContext、DbInitializerは以下の通りです。

C#

1using System; 2using System.Collections.Generic; 3using System.Linq; 4using System.Threading.Tasks; 5using DBAccessSample.Models; 6using Microsoft.EntityFrameworkCore; 7 8namespace WebApplication.Data 9{ 10 public class MyDbContext : DbContext 11 { 12 public MyDbContext(DbContextOptions<MyDbContext> options) : base(options) { } 13 14 public DbSet<Animal> Animals { get; set; } 15 16 public DbSet<Plant> Plants { get; set; } 17 } 18} 19

C#

1sing System; 2using System.Collections.Generic; 3using System.Linq; 4using System.Threading.Tasks; 5using WebApplication.Models; 6using Microsoft.EntityFrameworkCore; 7 8namespace WebApplication.Data 9{ 10 public class DbInitializer 11 { 12 public static void Initialize(MyDbContext context) 13 { 14 context.Database.EnsureCreated(); 15 16 if (context.ProgressTables.Any()) 17 { 18 return; // DB has been seeded 19 } 20 21 //Animal 22 var animals = new Animal[] 23 { 24 new Animal{ 25 //初期データ 26 } 27 28 }; 29 foreach (var tmp in animals) 30 { 31 context.Animals.Add(tmp); 32 } 33 context.SaveChanges(); 34 35 //Plant 36 var plants = new Plant[] 37 { 38 new Plant{ 39 //初期データ 40 } 41 42 }; 43 foreach (var tmp in plants) 44 { 45 context.Plants.Add(tmp); 46 } 47 context.SaveChanges(); 48 } 49 } 50}

疑問点が不明瞭で分かりにくいかと思いますが、よろしくお願いします。

参考URL

https://tech-blog.cloud-config.jp/2019-09-10-create-a-netcore-webapp-loosely-and-easily-part1/
https://qiita.com/KktkiY/items/f28528916e97310262e0

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

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

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

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

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

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

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

退会済みユーザー

退会済みユーザー

2020/12/03 09:07

> AnimalもしくはPlantのページで追加したデータや初期データをViewModelのページに反映させる、またLivingViewModelの方で編集したデータをAnimalもしくはPlantのページに反映させる 意味が分かりません。もう少し詳しく具体例など挙げて説明できませんか?
K-actus

2020/12/03 09:23

AnimalのページにあるCreate Newのリンクからデータを作成した際に、AnimalのModelを継承しているはずのViewModelのページに追加したデータが反映されません。 その追加したデータが反映されるようなViewModelのControllerの書き方を教えてほしいです。
退会済みユーザー

退会済みユーザー

2020/12/04 04:08 編集

「AnimalのページにあるCreate Newのリンク」とか言われても、質問に書いてないことなので分かりません。「AnimalのModelを継承しているはずのViewModelのページ」というのも質問に書いてないことなので分かりません。
退会済みユーザー

退会済みユーザー

2020/12/04 04:13

回答が必要なら、回答者が分からないと言っていることに対して追加情報を出して分かってもらえるようにする努力をしませんか。
K-actus

2020/12/04 04:22

すみません返信が遅れました。 CreateNewのリンクはDbContextとModelでスキャフォールディングしたら自動で生成される認識なんですけど共通ではないんですか? ViewModelのページについては2つ目の参考リンクを元にほぼそのまま実装しました。
退会済みユーザー

退会済みユーザー

2020/12/04 05:26

> CreateNewのリンクはDbContextとModelでスキャフォールディングしたら自動で生成される認識なんですけど共通ではないんですか? 自動生成されたコードの少なくとも Controller はコピペして質問欄に書いてください。回答者の想像力に期待しないできちんと質問に書いてください。想像で答えて、想像が違っていると、混乱を招くばかりです。ここ Teratail には回答者の想像の斜め上のことをしている質問者さんが多いのです。 「AnimalのModelを継承しているはずのViewModelのページ」というのも質問に書いてないので分かりません。こちらもコードをアップして説明してください。
BluOxy

2020/12/04 06:36

> AnimalもしくはPlantのページで追加したデータや初期データをViewModelのページに反映させる、またLivingViewModelの方で編集したデータをAnimalもしくはPlantのページに反映させるControllerの書き方 Animal Plant と ViewModel をEF上でリレーションさせれば良いと思います。 もっとも、そうなるとViewModelという命名は不適切になると思いますが…。
退会済みユーザー

退会済みユーザー

2020/12/04 07:12

> 以下現在のViewModelのControllerです。 の LivingViewModelsController の Index では、実際には Animals.Add(new Animal { /*初期データ*/ }); と Plants.Add(new Plant { /*初期データ*/ }); のデータを表示したいのではなくて、 > 以下AnimalのControllerです。 の AnimalsController コードの Index で表示される Animal のレコード一覧の Table と、もう一つ他にあると思われる PlantController の Index で表示される Plant のレコード一覧の Table を、参考にしている記事 https://qiita.com/KktkiY/items/f28528916e97310262e0 にあるように並べて表示したいということですか? そして、表示するだけでなく、LivingViewModelsController に DELETE, UPDATE, CREATE 機能を持たせたいと言ってますか?
K-actus

2020/12/04 07:19

前半部分はその通りです。 >そして、表示するだけでなく、LivingViewModelsController に DELETE, UPDATE, CREATE 機能を持たせたいと言ってますか? LivingViewModelsController にCreate, Update, Delete機能を持たせるのはあったら嬉しいくらいなので、 難しそうでしたらReadだけで構いません。
guest

回答2

0

ベストアンサー

以下現在のViewModelのControllerです。

の LivingViewModelsController の Index では、実際には Animals.Add(new Animal { /初期データ/ }); と Plants.Add(new Plant { /初期データ/ }); のデータを表示したいのではなくて、

以下AnimalのControllerです。

の AnimalsController コードの Index で表示される Animal のレコード一覧の Table と、もう一つ他にあると思われる PlantController の Index で表示される Plant のレコード一覧の Table を、参考にしている記事 https://qiita.com/KktkiY/items/f28528916e97310262e0 にあるように並べて表示したいということだそうですので・・・

LivingViewModelsController のコードを以下のようにすればよさそうです。これが質問者さんのやりたいことと異なる場合は、どう異なるか下のコメント欄に書いてください。

namespace WebApplication.Controllers { public class LivingViewModelsController : Controller { private readonly MyDbContext _context; public LivingViewModelsController(MyDbContext context) { _context = context; } public async Task<IActionResult> Index() { LivingViewModel myView = new LivingViewModel(); myView.Animals = await _context.Animals.ToListAsync(); myView.Plants = await _context.Plant.ToListAsync(); return View(myView); } } }

表示するだけでなく、LivingViewModelsController に DELETE, UPDATE, CREATE 機能を持たせるというのは、並べて表示する Table に、AnimalsController の Index、PlantController の Index で表示される Table と全く同じ Create, Edit, Delete, Detail のリンクを持たせて、AnimalsController, PlantController に飛ばしてそれで行うようにしてはいかがですか?

投稿2020/12/04 07:32

編集2020/12/04 07:52
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

退会済みユーザー

退会済みユーザー

2020/12/04 07:54

最初に書いたコードが間違っていて(コンストラクタの名前、await が欠落)訂正しましたので注意してください。
K-actus

2020/12/07 01:31 編集

該当ページを開こうとするとSqlException: Invalid object name 'Plants'. のエラーが出ます。 LivingViewModelについてDbContextを修正する必要はありますか?
退会済みユーザー

退会済みユーザー

2020/12/04 09:18

それだけの情報では分からないですね。どこでどのようにするとそのエラーが出るかも書いてないし、ホントに情報不足です。回答者はスレッドに書いてあること以外は知り得ません。よく考えて質問してください。
退会済みユーザー

退会済みユーザー

2020/12/05 01:18

質問のコメント欄にも書きましたが、回答が必要なら、回答者が分からないと言っていることに対して追加情報を出して分かってもらえるようにする努力をしませんか。 LivingViewModelsController のコードを書き直したのであろうと想像してますが、そのコードを見せてもらわないと、あなたが何をしたかなんてのは分かりません。 これも質問のコメント欄に書きましたが、回答者の想像力に期待しないできちんと質問に書いてください。想像で答えて、想像が違っていると、混乱を招くばかりです。ここ Teratail には回答者の想像の斜め上のことをしている質問者さんが多いのです。 なお、質問者さんが書き直した LivingViewModelsController のコードを質問欄にアップする際は、元のコードを書き直すのではなく、追記する形で書いてください。このスレッドの Q&A の話につじつまが合わなくなって、あとで検索などでこのスレッドを訪れる人には訳が分からなくなりますので。
K-actus

2020/12/07 01:31 編集

返信が遅れて申し訳ありません。 LivingViewModelsControllerのコードは、 myView.Plants = await _context.Plant.ToListAsync(); の右辺をPlantからPlantsにした以外SurferOnWwwさんが載せてくれたコード通りに修正しました。 DbContextも質問文から修正していません。
退会済みユーザー

退会済みユーザー

2020/12/07 01:31

エラーは await _context.Animals.ToListAsync() で出るのですよね? そうであればAnimalsController の Index メソッドの await _context.Animals.ToListAsync() でも同じエラーが出るはずなのですが? でも、質問を読む限り AnimalsController の Index メソッドではエラーにならず、期待通り Animals のリストが表示されるように思えます。 とすると、質問に書いてないどこか別のところで何かの違うことをやっていて、それが原因だとしか思えないです。どこか違わないか探してみてください。
K-actus

2020/12/07 01:40

すみません、解決しました。 エラーが出てたのはPlantsの方で、原因はテーブルが存在してないからでした。 ありがとうございました。
guest

0

リレーションシップ を構築してください。

C#

1public class Living 2{ 3 public int LivingId { get; set; } 4 public List<Animal> Animals { get; set; } 5 public List<Plant> Plants { get; set; } 6} 7 8public class Animal 9{ 10 public int AnimalId { get; set; } 11 public string Name { get; set; } 12 13 public int LivingId { get; set; } 14 public Living Living { get; set; } 15} 16 17public class Plant 18{ 19 public int PlantId { get; set; } 20 public string Name { get; set; } 21 22 public int LivingId { get; set; } 23 public Living Living { get; set; } 24} 25 26public class MyDbContext : DbContext 27{ 28 public MyDbContext(DbContextOptions<MyDbContext> options) : base(options) { } 29 public DbSet<Living> Livings { get; set; } 30 public DbSet<Animal> Animals { get; set; } 31 public DbSet<Plant> Plants { get; set; } 32}

上記をコードファーストでマイグレーションしてください。

リレーションシップを構築し、関連データの読み込みを行うことによって、例えば AnimalController から特定の Animal エンティティを変更したとき、対象のエンティティはリレーションしている Living エンティティの Animals プロパティから参照できるので、変更後のエンティティを Living エンティティからも取得できるようになります。

具体的には上記エンティティに対してLINQ to EntitiesのIncludeメソッドを利用することでプロバイダーから関連のデータを一括で読み込めます。

投稿2020/12/04 07:09

編集2020/12/07 10:20
BluOxy

総合スコア2663

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

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

退会済みユーザー

退会済みユーザー

2020/12/05 08:48 編集

質問者さんのやりたいことは、AnimalsController コードの Index で表示される Animal のレコード一覧の Table と、もう一つ他にあると思われる PlantController の Index で表示される Plant のレコード一覧の Table を、参考にしている記事 https://qiita.com/KktkiY/items/f28528916e97310262e0 にあるように並べて表示したいということだそうですので、上記の回答はその目的を果たすための直接の回答になってないと思いますが、そこはちょっと置いといて・・・ > 例えば AnimalController から特定の Animal エンティティを変更したとき、対象のエンティティはリレーションしている Living エンティティの Animals プロパティから参照できるので、変更後のエンティティを Living エンティティからも取得できるようになります。 そこは具体的にどのようにするのでしょうか? .NET Framework の Enitity Framework ですと、ナビゲーションプロパティで遅延読み込みが可能なので、Living クラスの Animals プロパティに virtaul を付与しておけばプロパティにアクセスしたときに DB から関連データを読み込むことができるのですが、回答のコードのプロパティには virtual がないです。 virtual を付与して遅延読み込みを有効にしても、今度は例えば View でループを回してナビゲーションプロパティにアクセスすると、N+1 問題が発生するという別の問題も考えなければならなそうです。 さらに、Core では遅延読み込みはデフォルトで無効なので(質問者さんのアプリは Core 2.2 だそうです)、Living の Animals プロパティが指す List<Animal> オブジェクトはあらかじめ初期化してその参照をプロパティに代入しておかなければならないのですが、そこのところはどうするのでしょう。
BluOxy

2020/12/07 00:33

はい、複数TableをViewModel経由で並べて表示する方法ではなく、新規のTableを定義してそれを直接表示する方法になります。Livingクラスの Animals, PlantsをそれぞれRazor構文で表示することで、やりたいことは結果的に満たせると思っています。 > 具体的にどのようにするのでしょうか? ご指摘の通り、関連データの取得方法を具体的に回答していませんでした。 いくつかあるので、方法が記載されているMicrosoftの記事を添付します。回答に書いたコードでは、Includeメソッドを通して取得できる認識です。(検証はしていません) https://docs.microsoft.com/ja-jp/ef/core/querying/related-data/ ※ソースコードについては、Microsoftの記事にあるBlob, Post クラスにvirtualが無かったので、まずはそれ等にならうよう愚直に実装しました。
退会済みユーザー

退会済みユーザー

2020/12/07 02:11 編集

回答の説明では具体的にどのようにするのか少なくとも自分には分からなかったです。 > 回答に書いたコードでは、Includeメソッドを通して取得できる認識です。 そういう話であれば、上の回答に書いてあった、 > 例えば AnimalController から特定の Animal エンティティを変更したとき、対象のエンティティはリレーションしている Living エンティティの Animals プロパティから参照できるので、変更後のエンティティを Living エンティティからも取得できるようになります。 の説明の前に、Linq のメソッドではこれこれこういう形で Include 使った式で一括で SQL Server からデータを読み込んで Living オブジェクトを生成し・・・と言うことを書いておいていただけたらと思います。 > ソースコードについては、Microsoftの記事にあるBlob, Post クラスにvirtualが無かったので、まずはそれ等にならうよう愚直に実装しました。 Entity Framework Core では遅延読み込みはデフォルトで無効なので virtual を付与しても意味がないからでしょう。(参考にされた記事の「遅延読み込み」のリンク先では遅延読み込みを有効にして virtual を付与しています)
BluOxy

2020/12/07 10:17

ありがとうございます。追記しました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問