Entity Frameworkのコア1対多の関係

c# entity-framework-core one-to-many

質問

私は、1対多の関係を持つコードの最初のデータモデルを構築しようとしています。

ユーザーには1対1の役割を持つUserDTOとRoleDTOモデルがあります。

RoleDTOの簡略化されたコードは次のとおりです。

internal class RoleDTO
{
    public UserDTO User { get; set; }

    public string Value { get; set; }

    public RoleDTO()
    {

    }
}

そして、単純化されたUserDTO:

internal class UserDTO
{
    public string Email { get; set; }

    public string FullName { get; set; }

    public string UserName { get; set; }

    public virtual ICollection<RoleDTO> Roles { get; set; }

    public UserDTO()
    {

    }
}

そして最後にDBContextから継承するクラス

class StorageContext : DbContext
{
    public DbSet<UserDTO> Users { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer(@"My_Connection_String");
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<UserDTO>().HasKey(entity => entity.Email);
        modelBuilder.Entity<UserDTO>().HasMany(entity => entity.Roles);

        modelBuilder.Entity<RoleDTO>().HasOne<UserDTO>().WithMany(x => x.Roles);
        modelBuilder.Entity<RoleDTO>().HasKey(x => x.Value);
    }
}

追加のマイグレーションを実行しても、データベースまたはマイグレーションフォルダがなく(そして、たとえカラムがあってもそれを実行しても)、ユーザーの電子メールアドレスを参照する余分な列がロールテーブルに作成されます。

私は自分のロールテーブルに2つのカラムを必要とします.1つはユーザの電子メールアドレスで、User電子メールPKへのFK、もう1つは外部キーと組み合わされた文字列値です。 。下の図:

*******************************
* Role                        *
*******************************
* User_Email - string/varchar *
* Value - string /varchar     *
*******************************
FK - User_Email to User table Email column
PK - User_Email, Value compound primary key

どのように流暢なAPIまたはデータの注釈を使用してこれを達成するために知っていますか?

ありがとう!

受け入れられた回答

まず第一に、クラスUserDTOUser_Emailという名前のプロパティがありません。 EFを使用してモデル内にシャドウプロパティを定義することはできますが、モデルに入れることを考慮して、クラスpublic string User_Emailプロパティを定義する必要があります

Fluent APIを使用して、上記のプロパティをクラスに定義したり、モデルで定義されているシャドウプロパティを取得したりすると、

複合主キーを定義するには、 HasKey APIを使用する必要があります。データ注釈を使用して複合主キーを定義することはできません。

User_Email, Valueを複合PKとして定義するにはUser_Email, Value次のコードをOnModelCreating記述しOnModelCreating (そのようにすると、シャドウプロパティを定義した後に)

modelBuilder.Entity<UserDTO>().HasKey(e => new { e.User_Email, e.Value });

ForeignKeyAttributeシップに外部キープロパティを指定するには、fkプロパティ/ナビゲーションでForeignKeyAttributeを使用するか、 HasForeignKey APIを使用できます。

設定するにはUser_EmailにFKするUserDTOテーブル、と仮定しUserDTO UserRoleDTOICollection<RoleDTO> RolesUserDTOこの関係のナビゲーションです。

データアノテーションを使用する場合は、 User_EmailプロパティにForeignKey("User")User_Emailするか、どちらかのナビゲーション( User / Roles )にForeignKey("User_Email")ForeignKey("User_Email")します。 User_Emailをシャドウプロパティとして使用している場合は、これを使用できないことを覚えておいてください。

Fluent APIを使用して、次のコードをOnModelCreating関係を完全に設定します

modelBuilder.Entity<RoleDTO>().HasOne(e => e.User).WithMany(e => e.Roles).HasForeignKey(e => e.User_Email);

上記の例では、 User_Emailを外部キープロパティとして使用するUserRolesナビゲーションを使用して1 User_Email関係が作成されます。

コードが正しく機能しなかった理由は

  1. HasKeyを使用して、コンポジットPKの代わりに単一のプロパティPKを定義しました。
  2. HasForeignKeyメソッドを使用して外部キープロパティを指定していないので、EFによってシャドウプロパティが追加されます。さらに、関係設定では、 Rolesナビゲーションのみを使用しました。 EFは、 Userナビゲーションを使用して別の関係を作成しようと試み、事実上UserDTORoleDTO間に2つの関係を作ります。これは、EFが慣習的に外部キープロパティとして使用するシャドープロパティを作成したため、余分な列がある理由です。

人気のある回答

私はあなたがこれで何を達成しようとしているのかよくわかりませんが、ORMの複合キーを使って作業することは複雑であり、予測不可能な領域になる可能性があります。だから実際の正当な理由がない限り、コンポジットキーに反するようにアドバイスします。

私はどこでもPKとして電子メールアドレスを使用しないことをお勧めします。一意の生成Int32 / Int64またはGuidを主キーとして使用します(これは、関係を設定するとRolesテーブルに外部キーとして反映されます)。それに対するユニークな制約。移行スクリプトに索引を追加できます。少なくともこの方法では、電子メールアドレスが変更された場合(それが必要な場合)、身元を保つことができます。

私はこれが役立つことを願っています



Related

ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ
ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ