28 votes

Entity Framework Code-First Issues (table SimpleMembership UserProfile)

Si vous avez utilisé ASP.NET MVC 4, vous remarquerez que l'application Internet utilise par défaut le fournisseur SimpleMembership, ce qui est très bien et fonctionne parfaitement.

Le problème vient de la génération de la base de données par défaut, ils ont un POCO pour la base de données. UserProfile défini comme suit :

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

qui est ensuite généré comme ceci :

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

Cela fonctionne bien, la base de données est générée sans problème et fonctionne sans problème. Cependant, si je modifie le POCO comme ceci et que je supprime la base de données :

[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; }
}

Seules les 2 premières colonnes sont générées, UserId y EmailAddress . Le code fonctionne parfaitement (il parle de la connexion et de l'enregistrement), mais il est évident qu'aucune de mes autres données utilisateur n'est stockée.

Est-ce que je rate quelque chose ? La base de données devrait sûrement être générée à partir de l'ensemble des données de la base de données. UserProfile objet.

47voto

LeLong37 Points 1165

1 - Vous devez activer les migrations, de préférence avec EntityFramework 5. Utilisez Enable-Migrations dans le gestionnaire de paquets NuGet.

2 - Déplacez votre

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

à votre méthode Seed dans votre classe YourMvcApp/Migrations/Configuration.cs

    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"});
    }

Maintenant, EF5 va se charger de créer votre table UserProfile, après quoi vous allez appeler WebSecurity.InitializeDatabaseConnection pour enregistrer SimpleMembershipProvider avec la table UserProfile déjà créée, en indiquant également à SimpleMembershipProvider les colonnes UserId et UserName. Je montre également un exemple de la façon dont vous pouvez ajouter des utilisateurs, des rôles et associer les deux dans votre méthode Seed avec des propriétés/champs personnalisés de UserProfile, par exemple le numéro de portable d'un utilisateur.

3 - Maintenant, lorsque vous exécutez update-database depuis la console du gestionnaire de paquets, EF5 va approvisionner votre table avec toutes vos propriétés personnalisées.

Pour des références supplémentaires, veuillez vous référer à cet article avec le code source : http://blog.longle.net/2012/09/25/seeding-users-and-roles-with-mvc4-simplemembershipprovider-simpleroleprovider-ef5-codefirst-and-custom-user-properties/

5voto

Rudi Visser Points 11599

Il semble que j'ai finalement compris, et que ce n'était peut-être qu'un énorme malentendu.

En fait, je m'attendais ((IObjectContextAdapter)context).ObjectContext.CreateDatabase(); pour faire ce qu'il ne fait pas, c'est-à-dire créer toutes les tables de la base de données qui n'existent pas, ou simplement les mettre à jour si elles existent et qu'elles sont différentes.

Ce qui se passe en fait, c'est qu'il exécute littéralement un CREATE DATABASE qui, pour moi, est la chose la plus inutile qui soit. À moins que vous ne travailliez dans un environnement vraiment étrange, vous aurez toujours une base de données sur l'arrêt et donc elle existera toujours (et par conséquent la création de table ne se produira jamais !), je préférerais ne pas donner aux utilisateurs du monde réel l'accès pour créer une base de données de toute façon.

Quoi qu'il en soit, j'ai résolu mon problème spécifique de vouloir UserProfile (et les tables associées) pour créer la base de données en utilisant la commande DropCreateDatabaseIfModelChanges et de forcer une initialisation comme ci-dessous :

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);
    }
}

cela fonctionne et c'est parfait pour le développement mais c'est plutôt inutile dans la pratique car cela va littéralement laisser tomber la base de données et la recréer à partir de zéro si le modèle change. Pour moi, cela rend la pratique du code first presque inutile dans sa forme par défaut et je finirai probablement par revenir à une génération edmx à partir de la base de données.

Le "mystère" derrière le UserProfile toujours en cours de création est que WebSecurity.InitializeDatabaseConnection initialisera la table si elle n'existe pas, en se basant sur les champs que vous lui passez, ce qui explique pourquoi la fonction EmailAddress a été créé à la place de UserName parce que je l'avais changé en ceci.

2voto

rufo Points 1244

J'avais le même problème. J'ai ajouté du code pour que les migrations se produisent juste avant le "CreateDatabase" dans le SimpleMembershipInitializer.

Cela a réglé le problème pour moi, sauf que je crois que maintenant mes migrations vont être appliquées dans Azure indépendamment du paramètre dans le profil de publication.

  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
            {....

0voto

Siva Points 301

Si vous n'avez pas l'intention d'apporter des modifications une fois que le système est en ligne et que cela ne se produit que dans le cadre du développement et que vous ne souhaitez pas permettre les migrations. Essayez de tronquer la table __MigrationHistory.

truncate table __MigrationHistory

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X