1. ホーム
  2. entity-framework

[解決済み] Entity Frameworkにおける一意性制約 Code First

2022-07-12 17:19:27

質問

質問

フルエント構文または属性のいずれかを使用して、プロパティに一意制約を定義することは可能ですか? そうでない場合、回避策はありますか?

主キーを持つユーザークラスがありますが、電子メールアドレスも一意であることを確認したいと思います。これは、データベースを直接編集することなく可能ですか?

解決策 (マットの回答に基づいて)

public class MyContext : DbContext {
    public DbSet<User> Users { get; set; }

    public override int SaveChanges() {
        foreach (var item in ChangeTracker.Entries<IModel>())
            item.Entity.Modified = DateTime.Now;

        return base.SaveChanges();
    }

    public class Initializer : IDatabaseInitializer<MyContext> {
        public void InitializeDatabase(MyContext context) {
            if (context.Database.Exists() && !context.Database.CompatibleWithModel(false))
                context.Database.Delete();

            if (!context.Database.Exists()) {
                context.Database.Create();
                context.Database.ExecuteSqlCommand("alter table Users add constraint UniqueUserEmail unique (Email)");
            }
        }
    }
}

どのように解決するのですか?

私が知る限り、Entity Frameworkでこれを行う方法は今のところありません。 しかし、これはユニーク制約だけの問題ではありません。インデックスやチェック制約、場合によってはトリガーや他のコンストラクトも作成したいかもしれません。 以下は、使用できる簡単なパターンです。 しかし、これはデータベースに依存しません。

public class MyRepository : DbContext {
    public DbSet<Whatever> Whatevers { get; set; }

    public class Initializer : IDatabaseInitializer<MyRepository> {
        public void InitializeDatabase(MyRepository context) {
            if (!context.Database.Exists() || !context.Database.ModelMatchesDatabase()) {
                context.Database.DeleteIfExists();
                context.Database.Create();

                context.ObjectContext.ExecuteStoreCommand("CREATE UNIQUE CONSTRAINT...");
                context.ObjectContext.ExecuteStoreCommand("CREATE INDEX...");
                context.ObjectContext.ExecuteStoreCommand("ETC...");
            }
        }
    }
}

別の選択肢は、ドメインモデルがデータベースでデータを挿入/更新する唯一の方法である場合、一意性の要件を自分で実装して、データベースを除外することができます。 これはより移植性の高いソリューションであり、コードの中でビジネスルールについて明確にすることを強制しますが、無効なデータがバックドアされる可能性があるため、データベースをオープンにしておきます。