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

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

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

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

MVC

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

ASP.NET

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

Q&A

解決済

1回答

1611閲覧

ASP.NET MVC5 Identityでのエラー 'IdentityUserLogin' にはキーが定義されていません

step.step.step

総合スコア4

C#

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

MVC

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

ASP.NET

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

0グッド

0クリップ

投稿2021/06/20 17:17

編集2021/06/22 14:05

visual studio 2019
ASP.NET MVC5
で学習をしています。

------以下追記します 2021/06/22---------

いま、作りたいなと思っているのは架空の学校で登校時間、下校時間などを各ユーザーが
自分で登録するサイトです。

ユーザーさんにはidentity機能で個別にログインしてもらい、登校時間など入力して
submitボタンを押すと、その登校時間などの情報をRecordsテーブルに登録されます。
その時、Recordsテーブルにはどのユーザーさんの情報か識別できるようにするために、
string のApplicationUserId列を作って自動的にApplicationUserIdを登録させようと思っています。

また、過去に登録したことのあるユーザーさんが自分の登録した分の結果を一覧でみることが
できるようにするためにも、ApplicationUserId列は使用したいと考えています。

つまり、各ユーザーさんはログインして自分の分しか登録できないし、自分の分しか登録されたものを
みれないようなサイトをidentityを使って作成しようと考えています。

はじめは、
Modelsに

c#

1public class Record 2{ 3 public int Id { get; set; } 4 5 //~中略~ 6 7 public string ApplicationUserId { get; set; } 8 9 public virtual ApplicationUser ApplicationUser { get; set; } 10} 11

として、コンテキストは

c#

1public class RecordContext:DbContext 2 3{ 4public DbSet<Record> Records { get; set; } 5}

で作っていたのですが、テストのユーザーを作成して、データを登録してもみてもRecordsテーブルのApplicationUserId はNullのままで、ユーザー識別の役に立ちませんでした。

ログインして、登校時間などを登録するだけではダメそうなので、登録と同時にコントールで、ApplicationUser からIdを取り出して、RecordsテーブルのApplicationUserIdに登録するのかなと思い、
初めの質問のようにコンテキストの中に
public DbSet<ApplicationUser> ApplicationUser { get; set; }
を入れて作成しようと思いました。

-----追記終了--------------------------------

Identity機能を使おうとしているのですが、
コンテキストクラスを以下のようにしたところ

C#

1 public class RecordContext:DbContext 2 { 3 public DbSet<Record> Records { get; set; } 4 public DbSet<ApplicationUser> ApplicationUser { get; set; } 5 }

下のようなエラーが出てきます。

AttendanceMg1.Models.IdentityUserLogin: : EntityType 'IdentityUserLogin' にはキーが定義されていません。この EntityType にはキーを定義してください。
AttendanceMg1.Models.IdentityUserRole: : EntityType 'IdentityUserRole' にはキーが定義されていません。この EntityType にはキーを定義してください。
IdentityUserLogins: EntityType: EntitySet 'IdentityUserLogins' はキーが定義されていない型 'IdentityUserLogin' に基づいています。
IdentityUserRoles: EntityType: EntitySet 'IdentityUserRoles' はキーが定義されていない型 'IdentityUserRole' に基づいています。
'

IdentityUserLogin、IdentityUserRoleに主キーを定義すれば良いのかなと思うのですが、間違ってないでしょうか。
また、まちがってないとするとどのようにすれば主キーは定義できるでしょうか。
なにとぞ、よろしくお願いいたします。

-----現状についての追記 2021/06/22--------
SurferOnWww さんからのアドバイスで余計なことを考えずに、データを登録するコントロールの中で、
ApplicationUserIdを登録するだけでよいのではと、考えてみました。

早速、以下でやってみました。
コンテキスト

C#

1public class RecordContext:DbContext 2{ 3 public DbSet<Record> Records { get; set; } 4 //public DbSet<ApplicationUser> ApplicationUser { get; set; } 5} 6

コントロール

c#

1[HttpPost] 2[ValidateAntiForgeryToken] 3public ActionResult Create([Bind(Include = "Id,YMD,DOW,Attend,Leave,Task,Updatetime")] Record record) 4{ 5  if (ModelState.IsValid) 6  { 7   record.ApplicationUserId = User.Identity.GetUserId(); 8   db.Records.Add(record); 9   db.SaveChanges(); 10   return RedirectToAction("Index"); 11  } 12 return View(record); 13}

ApplicationUserIdを登録することができて、一覧画面でもログイン中のユーザーさん分だけの表示ができました!!

回答をされることなく追加質問だけで、わたしのやりたいことの実現まで導いてくださってありがとうございます。

ただ、こんなやり方が本当に良いのか解ってないですし、何より初めの質問内容がどうしてありえないことなのかもまったく解っていません。
ご負担になってしまうのかもしれませんが、わたしの実現の仕方のついてのご意見や、初めのコンテキストがありえないことであり、得ないエラーがでていることについての概略でも教えて頂けると嬉しいです。
なにとぞ、よろしくお願いします。

-----現状についての追記終了--------

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

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

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

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

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

退会済みユーザー

退会済みユーザー

2021/06/20 22:39 編集

そもそものやりたいことは何か、できるだけ詳しく書いてください (質問欄に追記してください)。 XY 問題になっているような気がしますので。
退会済みユーザー

退会済みユーザー

2021/06/21 02:58 編集

「XY 問題」とはググれば出てくるのですが、どういうことかと言うと、質問者さんに X という課題があって、それを解決するために質問者さんが Y という方法を考えて、Y に関する質問をした。しかし、Y は X の解決にはならないので、Y に関していくら Q&A をしても一向に解決に至らず、お互い時間と労力の無駄になる可能性が高いということです。なので、X は何かと聞いてます。
退会済みユーザー

退会済みユーザー

2021/06/21 02:53

ちなみに、はっきり言って質問に書いてあることは、あり得ないことをしてあり得ないエラーが出ているとしか思えません。「コンテキストクラスを以下のようにした」とありますが、少なくとも自分の知識の範囲では、それがそもそもあり得ないことです。 もしそうではなかったとしても、質問に書いてある情報だけでは、質問に書いてある情報以外は知り得ない第三者には原因も解決策も分からないということを認識してください。
step.step.step

2021/06/21 13:46

ありがとうございます。 そっか。ありえないことやってしまっているんですね。。。 いま、作りたいなと思っているのは架空の学校で登校時間、下校時間などを各ユーザーが 自分で登録するサイトです。 ユーザーさんにはidentity機能で個別にログインしてもらい、登校時間など入力して submitボタンを押すと、その登校時間などの情報をRecordsテーブルに登録されます。 その時、Recordsテーブルにはどのユーザーさんの情報か識別できるようにするために、 string のApplicationUserId列を作って自動的にApplicationUserIdを登録させようと思っています。 また、過去に登録したことのあるユーザーさんが自分の登録した分の結果を一覧でみることが できるようにするためにも、ApplicationUserId列は使用したいと考えています。 つまり、各ユーザーさんはログインして自分の分しか登録できないし、自分の分しか登録されたものを みれないようなサイトをidentityを使って作成しようと考えています。 はじめは、 Modelsに public class Record { public int Id { get; set; } ~中略~ public string ApplicationUserId { get; set; } public virtual ApplicationUser ApplicationUser { get; set; } } として、コンテキストは public class RecordContext:DbContext { public DbSet<Record> Records { get; set; } } で作っていたのですが、テストのユーザーを作成して、データを登録してもみてもRecordsテーブルのApplicationUserId はNullのままで、ユーザー識別の役に立ちませんでした。 ログインして、登校時間などを登録するだけではダメそうなので、登録と同時にコントールで、ApplicationUser からIdを取り出して、RecordsテーブルのApplicationUserIdに登録するのかなと思い、 初めの質問のようにコンテキストの中に  public DbSet<ApplicationUser> ApplicationUser { get; set; } を入れて作成しようと思いました。
step.step.step

2021/06/21 13:49

と、ここまでお返事の下書きを書いていてハッと思いました。 余計なことを考えずに、データを登録するコントロールの中で、ApplicationUserIdを登録するだけでよいのではと。 早速、以下でやってみました。 コンテキスト   public class RecordContext:DbContext { public DbSet<Record> Records { get; set; } //public DbSet<ApplicationUser> ApplicationUser { get; set; } } コントロール [HttpPost] [ValidateAntiForgeryToken] public ActionResult Create([Bind(Include = "Id,YMD,DOW,Attend,Leave,Task,Updatetime")] Record record) { if (ModelState.IsValid) { record.ApplicationUserId = User.Identity.GetUserId(); db.Records.Add(record); db.SaveChanges(); return RedirectToAction("Index"); } return View(record); } ApplicationUserIdを登録することができて、一覧画面でもログイン中のユーザーさん分だけの表示ができました!! 回答をされることなく追加質問だけで、わたしのやりたいことの実現まで導いてくださってありがとうございます。 ただ、こんなやり方が本当に良いのか解ってないですし、何より初めの質問内容がどうしてありえないことなのかもまったく解っていません。 ご負担になってしまうのかもしれませんが、わたしの実現の仕方のついてのご意見や、初めのコンテキストがありえないことであり、得ないエラーがでていることについての概略でも教えて頂けると嬉しいです。 なにとぞ、よろしくお願いします。
step.step.step

2021/06/21 13:50

文中のコードのインデントが変になっていて申し訳ありません。コピペの仕方が下手でした。
退会済みユーザー

退会済みユーザー

2021/06/21 21:28 編集

やっぱり XY 問題でしたね。 今からでも遅くないので X (2021/06/21 22:46 の質問者さんのレス) を質問欄に追記してください。さらに、見直した現状 (2021/06/21 22:49 のこと) も質問欄に追記してください。
guest

回答1

0

ベストアンサー

質問のコメント欄の 2021/06/21 22:46 の質問者さんのコメントを見るとやはり XY 問題でしたね。

質問する際は Y だけの情報で聞くのではなく、必ず X も書くようにしてください。今からでも遅くないので質問欄のコメントの 2021/06/21 22:46 と 2021/06/21 22:49 を質問欄に追記してください。

初めの質問のようにコンテキストの中に
public DbSet<ApplicationUser> ApplicationUser { get; set; }
を入れて作成しようと思いました。

DbSet<ApplicationUser> のプロパティはフレームワークの中で Users という名前で定義済みです。(見かけ分かりませんが、自動生成されたコードの Models/IdentityModels.cs に ApplicationDbContext クラスがあって、その継承元で定義されているはずです。でなければ ASP.NET Identity は動かない)

最初の質問にあったエラーがどこで何の影響で出たのかは分かりませんが、何にせよ、やってはいけない場所での 2 重定義があり得ないことで、その結果あり得ないエラーが出たということには間違いなさそうです。

こんなやり方が本当に良いのか解ってないですし、

public DbSet<ApplicationUser> ApplicationUser { get; set; } をコメントアウトして期待通りにできたそうですが、そこはそれでもよいと思います。

ただ、ApplicationUser クラス、Record クラスにナビゲーションプロパティを定義して、Linq to Entities を使って取得した ApplicationUser エンティティからナビゲーションプロパティをたどって Record を取得するとか、逆に Record エンティティからナビゲーションプロパティをたどって ApplicationUser を取得したいという場合は話は別です。

その場合は、Models/IdentityModels.cs でコンテキストクラス/エンティティクラスを定義しなおして Migration をかけるということになります。

具体例として、以前作ったサンプルを載せておきます。Post(投稿の意味)というクラスを定義して、複数のユーザーが複数の投稿をするというケースを考えています。

自動生成された Models/IdentityModels.cs のコードに「追加」とコメントした部分を追加しています。

using System.Data.Entity; using System.Security.Claims; using System.Threading.Tasks; using Microsoft.AspNet.Identity; using Microsoft.AspNet.Identity.EntityFramework; // 追加 using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; namespace Mvc5App3.Models { // ApplicationUser クラスにさらにプロパティを追加すると、ユーザーのプロファイル データを追加できます。詳細については、https://go.microsoft.com/fwlink/?LinkID=317594 を参照してください。 public class ApplicationUser : IdentityUser { public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager) { // authenticationType が CookieAuthenticationOptions.AuthenticationType で定義されているものと一致している必要があります var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie); // ここにカスタム ユーザー クレームを追加します return userIdentity; } // 追加 public virtual IList<Post> Posts { get; set; } } // 追加 public class Post { [Key, Required] public int PostId { get; set; } [Required, MaxLength(128)] public string Title { get; set; } [Required, MaxLength(1024)] public string Content { get; set; } [Required, ForeignKey(nameof(User))] public string ApplicationUserId { get; set; } public virtual ApplicationUser User { get; set; } } public class ApplicationDbContext : IdentityDbContext<ApplicationUser> { public ApplicationDbContext() : base("DefaultConnection", throwIfV1Schema: false) { } public static ApplicationDbContext Create() { return new ApplicationDbContext(); } // 追加 public DbSet<Post> Posts { get; set; } } }

Migration を実行すると以下のテーブルが DB に生成されます。

イメージ説明

ApplicationUser に相当するテーブル dbo.AspNetUsers の Id 列に、dbo.Posts テーブルの ApplicationUserId 列から FK 制約が張られます。

もちろん上のコードのナビゲーションプロパティも働きます。

投稿2021/06/22 08:08

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

step.step.step

2021/06/22 14:18

ご回答、ありがとうございます。 >ただ、ApplicationUser クラス、Record クラスにナビゲーションプロパティを定義して、Linq to >Entities を使って取得した ApplicationUser エンティティからナビゲーションプロパティをたどって >Record を取得するとか、逆に Record エンティティからナビゲーションプロパティをたどって >ApplicationUser を取得したいという場合は話は別です。 やっぱり自分のやってたことは簡単過ぎだったんですね。 詳細なコードまで教えて頂き、すごく勉強になりました。
退会済みユーザー

退会済みユーザー

2021/06/22 21:38

> やっぱり自分のやってたことは簡単過ぎだったんですね。 ケースバイケースだと思います。 たとえば、回答の投稿の例で、匿名ユーザーも可能にしたい場合は FK 制約を張られては困るということもあるでしょうから。
step.step.step

2021/06/27 12:58

>たとえば、回答の投稿の例で、匿名ユーザーも可能にしたい場合は FK 制約を張られては困るということもあるでしょうから。 確かに、そうですね。そういったことも教えてもらって初めて気づくことができました。 今回は匿名ユーザーは不要として作成しようと思いますので、見せて頂いたサンプルを参考にして、 identityをつかったアプリにしようと思います。(ようやく今日それっぽくできました。。。)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問