web-dev-qa-db-ja.com

Entity Frameworkのコードファーストの問題(SimpleMembership UserProfileテーブル)

ASP.NET MVC 4を使用したことがある場合は、インターネットアプリケーションのデフォルトがSimpleMembershipプロバイダーを使用するようになっていることに気づくでしょう。

この問題はデフォルトのデータベース生成で発生し、UserProfileのPOCOが次のように定義されています。

[Table("UserProfile")]
public class UserProfile
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int UserId { get; set; }
    public string UserName { get; set; }
}

..これは次のように生成されます:

using (var context = new UsersContext())
{
    if (!context.Database.Exists())
    {
         // Create the SimpleMembership database without Entity Framework migration schema
         ((IObjectContextAdapter)context).ObjectContext.CreateDatabase();
    }
}

これは問題なく動作し、データベースは問題なく生成され、問題なく動作します。ただし、POCOを次のように変更してデータベースを削除する場合:

[Table("UserProfile")]
public class UserProfile
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int UserId { get; set; }
    public string EmailAddress { get; set; }

    public string FirstName { get; set; }
    public string Surname { get; set; }

    public string Country { get; set; }

    public string CompanyName { get; set; }
}

最初の2つの列UserIdEmailAddressのみが生成されます。コード的には(ログイン/登録を話す)うまく機能しますが、他のユーザーデータは保存されません。

ここで何か不足していますか?確かに、それはUserProfileオブジェクト全体に基づいてデータベースを生成するはずです。

28
Rudi Visser

私はついにこれを手に入れたようで、それはただ一つの大きな誤解だったのかもしれません。

結局のところ、私は((IObjectContextAdapter)context).ObjectContext.CreateDatabase();単純に実行しないこと、つまりデータベースに存在しないすべてのテーブルを作成すること、または実行するテーブルと異なるテーブルを更新すること。

実際に起こることは、文字通りCREATE DATABASEステートメント、これは私にとってこれまでで最も役に立たないことです。本当に奇妙な環境で作業しているのでない限り、データベースは常にオフになっているため、常に存在します(その結果、テーブルの作成は行われません)。実際のユーザーにはアクセスを許可しません。とにかくデータベースを作成します。

とにかく、UserProfile(および関連テーブル)にデータベースを作成して、DropCreateDatabaseIfModelChangesイニシャライザーを使用し、以下のような初期化を強制するという特定の問題を解決しました。

public SimpleMembershipInitializer()
{
#if DEBUG
    Database.SetInitializer<DataContext>(new DropCreateDatabaseIfModelChanges<DataContext>());
#else
    Database.SetInitializer<DataContext>(null);
#endif

    try
    {
        using (var context = new DataContext())
        {
            if (!context.Database.Exists())
            {
                ((IObjectContextAdapter)context).ObjectContext.CreateDatabase();
            }
            context.Database.Initialize(true);
        }

        WebSecurity.InitializeDatabaseConnection("DefaultConnection", "UserProfile", "UserId", "EmailAddress", autoCreateTables: true);
    }
    catch (Exception ex)
    {
        throw new InvalidOperationException("The ASP.NET Simple Membership database could not be initialized. For more information, please see http://go.Microsoft.com/fwlink/?LinkId=256588", ex);
    }
}

..これは機能し、開発に最適ですが、モデルが変更された場合、文字どおりデータベースを削除して最初から再作成するため、実際にはほとんど役に立ちません。私にとっては、これにより、コードファーストプラクティス全体がデフォルトの形式ではほとんど役に立たなくなり、おそらくDBからのedmx生成に戻ることになります。

作成中のUserProfileテーブルの背後にある「謎」はWebSecurity.InitializeDatabaseConnectionは、渡されたフィールドに基づいてテーブルが存在しない場合にテーブルを初期化します。これがEmailAddressではなくUserNameが作成された理由です。

5
Rudi Visser

1-できればEntityFramework 5で移行を有効にする必要があります。NuGetパッケージマネージャーでEnable-Migrationsを使用します。

2-移動

WebSecurity.InitializeDatabaseConnection("DefaultConnection", "UserProfile", "UserId", "EmailAddress", autoCreateTables: true); 

your Seedメソッドに

    protected override void Seed(UsersContext context)
    {
        WebSecurity.InitializeDatabaseConnection(
            "DefaultConnection",
            "UserProfile",
            "UserId",
            "UserName", autoCreateTables: true);

        if (!Roles.RoleExists("Administrator"))
            Roles.CreateRole("Administrator");

        if (!WebSecurity.UserExists("lelong37"))
            WebSecurity.CreateUserAndAccount(
                "lelong37",
                "password",
                new {Mobile = "+19725000000", IsSmsVerified = false});

        if (!Roles.GetRolesForUser("lelong37").Contains("Administrator"))
            Roles.AddUsersToRoles(new[] {"lelong37"}, new[] {"Administrator"});
    }

これで、EF5はUserProfileテーブルの作成を担当します。その後、WebSecurity.InitializeDatabaseConnectionを呼び出して、SimpleMembershipProviderを既に作成されているUserProfileテーブルに登録するだけで、SimpleMembershipProviderにUserIdとUserNameの列を通知します。また、ユーザー、ロールを追加する方法の例と、2つをSeedメソッドをユーザーのモバイル(番号)などのカスタムUserProfileプロパティ/フィールドに関連付ける)に関連付けています。

3-パッケージマネージャーコンソールからupdate-databaseを実行すると、EF5はテーブルにすべてのカスタムプロパティをプロビジョニングします

追加の参照については、ソースコードとともにこの記事を参照してください:http://blog.longle.net/2012/09/25/seeding-users-and-roles-with- mvc4-simplemembershipprovider-simpleroleprovider-ef5-codefirst-and-custom-user-properties /

47
LeLong37

私は同じ問題を抱えていました。 SimpleMembershipInitializerの "CreateDatabase"の直前に移行が行われるようにコードを追加しました。

これで問題が解決しましたが、パブリッシングプロファイルの設定に関係なく、移行がAzureに適用されると思います。

  private class SimpleMembershipInitializer
    {
        public SimpleMembershipInitializer()
        {
            Database.SetInitializer<WomContext>(null);

            // forcing the application of the migrations so the users table is modified before
            // the code below tries to create it. 
            var migrations = new MigrateDatabaseToLatestVersion<WomContext, Wom.Migrations.Configuration>();
            var context = new WomContext(); 
            migrations.InitializeDatabase(context); 

            try
            {....
2
rufo

システムの稼働後に変更を行う予定がなく、これは開発中にのみ発生し、移行を可能にすることに熱心ではない場合。テーブル__MigrationHistoryを切り捨ててみてください。

truncate table __MigrationHistory
0
Siva