Coreではない、ASP.NET MVCの時には問題のなかったのにCoreに変更してうまくいかなくなり対応したはずだが、諸事情によりソースがぶっ飛んで復活できなくなり困ったのだが、改めて対応したのでメモしておく。
①そもそもテーブルの設計がイマイチ
権限設定テーブルで以下のようなテーブル
CREATE TABLE [dbo].[authorities](
[authority] [int] NOT NULL,
[remarks] nvarchar NOT NULL,
[delete_flag] [bit] NOT NULL,
[create_date] datetime2 NULL,
[create_host_name] nvarchar NULL,
[modify_date] datetime2 NULL,
[modify_host_name] nvarchar NULL,
[timestamp] [timestamp] NULL,
...
テーブル名がエンティティにした際、Authorityとなり、その中でキーとなる項目が
authorityでプロパティは自動でAuthorityとなる。
本来であればid とするところ、設計が古いのでこのような設定となっている。
実際にエンティティを作成した際には
[Column("authority")]
[DisplayName("権限")]
public int Id { get; set; }
上記のように設定してある。
②リレーションする従業員テーブル
CREATE TABLE [dbo].[employees](
[id] [int] IDENTITY(1,1) NOT NULL,
[code] nchar NOT NULL,
[name] nvarchar NOT NULL,
[password] nvarchar NOT NULL,
[authority] [int] NOT NULL,
[branch_id] [int] NOT NULL,
テーブル上ではauthority同時でjoinしていた。本来であれば、その下の
branch_idのようにauthority_idとすべき、
実際にエンティティにした際は以下のようにした。
public partial class Employee
{
[Column("id")]
[DisplayName("ID")]
public int Id { get; set; }
// 未使用
public string Code { get; set; }
[Required(ErrorMessage = "{0}は必須入力です。")]
[StringLength(4, MinimumLength = 4, ErrorMessage = "{0}は4文字でお願いします。")]
[Column("code2")]
[DisplayName("社員コード")]
public string? Code2 { get; set; } = null!;
[Required(ErrorMessage = "{0}は必須入力です。")]
[StringLength(20, ErrorMessage = "{0}は20文字以内でお願いします。")]
[Column("name")]
[DisplayName("名前")]
public string Name { get; set; } = null!;
[Required(ErrorMessage = "{0}は必須入力です。")]
[StringLength(10, ErrorMessage = "{0}は10文字以内でお願いします。")]
[PasswordPropertyText]
[Column("password")]
[DisplayName("パスワード")]
public string? Password { get; set; }
[Required(ErrorMessage = "{0}は必須入力です。")]
[Column("authority")]
[DisplayName("権限")]
public int AuthorityId { get; set; }
[Required(ErrorMessage = "{0}は必須入力です。")]
[Column("branch_id")]
[DisplayName("所属営業所")]
public int BranchId { get; set; }
...
public virtual Authority Authority { get; set; }
public virtual Branch Branch { get; set; }
③このままだと、スキャフォールディングした際にエラーになる。
選択したコード ジェネレーターを実行中にエラーが発生しました!
'The 'Authority' property 'Employee.Authority' could not be mapped
because the database provider does not support this type. Consider converting the property value to
a type supported by the database using a value converter.
See https://aka.ms/efcore-docs-value-converters for more information.
Alternately, exclude the property from the model using the '[NotMapped]' attribute or by using
'Entity TypeBuilder.Ignore' in 'OnModelCreating'.'
④ソースが飛んだので以前にどういう対応をしたのか覚えてないのだが。。
copilotの力を借りて修正したのが以下(コンテキストを修正)
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
…
modelBuilder.Entity(entity =>
{
entity.HasKey(e => e.Id).HasName("PK_tblStaff");
…
// Authority エンティティとの関係を設定
entity.HasOne(e => e.Authority)
.WithMany(a => a.Employees)
.HasForeignKey(e => e.AuthorityId)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("FK_Employee_Authority");
});
今ここ。とりあえず、スキャフォールディングはできるようになった。
あと、注意としてAIに任せてたから気づかなかったけど、元々、
modelBuilder.Entityには、以下が当然、存在しているのに、
entity.Property(e => e.Authority).HasColumnName("authority");
上記の修正を「追加」でmodelBuilder.Entityの最後に追加したので、
スキャフォールディングが以下のエラーで通らなかった。。
The property or navigation Authority could not be added to the Employee
type because a property or navigation with the same name already exists on the Employee type.
このエラーのやり取りを繰り返してcopilotにAuthority エンティティとの関係を設定の修正ソースを教えてもらったので、あくまで、
entity.Property(e => e.Authority).HasColumnName("authority");を
修正することになる。
※要はentity.Property(e => e.Authority).HasColumnName("authority");を消して、// Authority エンティティとの関係を設定 以下のソースを追加する。