web-dev-qa-db-fra.com

Comment créer des champs supplémentaires personnalisés dans UserProfile dans MVC4

J'ai été confronté à une nouvelle fonctionnalité ASP MVC 4, elle est livrée avec un nouveau schéma de base de données d'appartenance et une nouvelle initialisation. mais maintenant je fais face à la méthode dans l'espace de noms des filtres dans le projet mvc 4 par défaut:

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

et tableau de profil utilisateur:

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

Mais la méthode InitializeDatabaseConnection ne génère que UserName et UserId dont j'ai besoin pour générer d'autres champs supplémentaires.

J'ai une bonne expérience de l'approche EF codeFirst, et dans ce cas, j'essaie de modifier la classe UserProfile:

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

Mais lorsque je régénère la base de données, je ne vois aucun changement, les champs de base de données personnalisés ne sont pas générés. Aidez-moi s'il vous plaît, comment puis-je créer des champs utilisateur personnalisés?

40
testCoder

Élaborer à partir de la réponse ci-dessus

Le WebSecurity.InitializeDatabaseConnection L'aide de la méthode indique que

Si vous souhaitez utiliser une table de base de données contenant des informations de profil utilisateur (noms d'utilisateurs, adresses e-mail, etc.), vous spécifiez une chaîne de connexion et un nom de table que le système d'appartenance utilise pour se connecter à ces informations. Si vous ne souhaitez pas utiliser une table de profil utilisateur existante, vous pouvez spécifier que la méthode InitializeDatabaseConnection () doit automatiquement créer la table de profil utilisateur. (Une base de données pour la table des profils utilisateur doit déjà exister.)

Donc, si nous voulons plus de champs dans la table UserProfile, nous devons juste nous assurer que nous créons une table de profil et exécuter la méthode InitializeDatabaseConnection une fois que la table est déjà en place.

Dans le modèle de projet MVC4.0 standard de VS2012, j'ai commenté le contrôleur de compte

[Authorize]
//[InitializeSimpleMembership]
public class AccountController : Controller
{

et déplacé InitializeDatabaseConnection dans l'EF Code First Database Initializer

public class MyDatabaseInit: DropCreateDatabaseAlways<MyDatabaseContext>
{
    protected override void Seed(MyDatabaseContext context)
    {
        SeedMembership();
    }

    private void SeedMembership()
    {
        WebSecurity.InitializeDatabaseConnection("MyDatabaseContext",
            "UserProfile", "UserId", "UserName", autoCreateTables: true);
    } 
}

s'assurer que InitializeDatabaseConnection s'exécute une fois que la table est déjà en place.

Ajout de la classe UserProfile à mon modèle EF Code First

public class MyDatabaseContext : DbContext
{
    public DbSet<UserProfile> UserProfiles { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
    }
}

Ajout du champ supplémentaire dans la table UserProfile

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

Tout ce dont vous avez besoin maintenant est de définir la stratégie d'initialisation de la base de données au démarrage de l'application et également d'appeler une requête sur la base de données pour vous assurer qu'elle est créée à ce stade, avant d'appeler un code d'autorisation/d'authentification.

protected void Application_Start()
{
   AreaRegistration.RegisterAllAreas();

   WebApiConfig.Register(GlobalConfiguration.Configuration);
   FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
   RouteConfig.RegisterRoutes(RouteTable.Routes);
   BundleConfig.RegisterBundles(BundleTable.Bundles);
   AuthConfig.RegisterAuth();

   Database.SetInitializer<MyDatabaseContext>(new MyDatabaseInit());
   new MyDatabaseContext().UserProfile.Find(1);
}
52
IMLiviu

Version non destructive basée sur la réponse et les commentaires d'IMLiviu:

Je suis juste tombé sur ce problème et j'ai dû dénouer la bonne façon de le faire à partir de la réponse + commentaires (+ essais et erreurs), alors j'ai pensé partager les résultats que vous pouvez couper et coller. Ceci est basé sur la réponse d'IMLiviu, donc un crédit complet pour eux. Il modifie les classes UserProfile et UserContext existantes car elles semblent directement compatibles avec EF telles quelles:

J'ai été horrifié de voir une suggestion qui impliquait de supprimer complètement une base de données, juste pour ajouter quelques tableaux, donc après avoir lu tous les commentaires et créé un prototype, voici le résultat.

1 - Arrêtez la création de Webmatrix

Arrêtez la création de matrice Web standard des tables d'appartenance (mettez en commentaire l'attribut [InitializeSimpleMembership]).

[Authorize]
//[InitializeSimpleMembership]
public class AccountController : Controller

2 - Créer une configuration de migration

Créez une classe de configuration de migration comme celle ci-dessous:

public class MigrationConfiguration : DbMigrationsConfiguration<UsersContext> 
{
    public MigrationConfiguration()
    {
        this.AutomaticMigrationsEnabled = true;  // This is important as it will fail in some environments (like Azure) by default
    }

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

3 - Supprimer la pluralisation de la création EF

Modifiez la classe UsersContext du fichier AccountModel.cs pour supprimer l'option de pluralisation (ajout de l'événement OnModelCreating):

public class UsersContext : DbContext
{
    public UsersContext() : base("DefaultConnection")
    {
    }

    public DbSet<UserProfile> UserProfiles { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
    }
}

4 - Ajouter de nouveaux champs à UserProfile

Ajoutez les champs supplémentaires dont vous avez besoin à UserProfile:

[Table("UserProfile")]
public class UserProfile
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int UserId { get; set; }
    public string UserName { get; set; }
    public string UserEmail { get; set; }  // <<<<<<<< E.G. THIS ADDED
}

5 - Migrer les tables au démarrage de l'application

Maintenant, lorsque l'application démarre, vous définissez la stratégie d'initialisation de la base de données et la déclenchez avec une lecture:

    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();

        WebApiConfig.Register(GlobalConfiguration.Configuration);
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);
        AuthConfig.RegisterAuth();

        Database.SetInitializer(new MigrateDatabaseToLatestVersion<UsersContext, MigrationConfiguration>());
        new UsersContext().UserProfiles.Find(1);
    }

Évidemment, vous devrez ajouter diverses instructions using pour que tout cela fonctionne, mais l'option clic droit résoudre le fera pour vous.

Notes complémentaires:

Si vous décidez (comme je l'ai fait) d'utiliser une table autre que UserProfile pour vos utilisateurs, vous devez modifier plusieurs entrées pour qu'elles correspondent.

  • Dans votre classe SimpleMembershipInitializer, vous devez référencer les nouveaux noms de table et de colonne
  • Dans le contrôleur de compte et les différentes vues de connexion et d'enregistrement, vous devez référencer vos nouveaux champs de modèle (si les noms ont changé)
  • Dans la classe UsersContext, vous pouvez laisser le nom de classe Userprofile tel quel, mais vous devez modifier l'attribut Table pour qu'il corresponde au nom de votre table.
  • Dans la classe UserProfile, vous devez renommer les champs pour qu'ils correspondent à vos nouveaux noms de champ de table.
  • Dans la base de données, vous devez supprimer la relation entre webpages_UsersInRoles et UserProfile et ajoutez une relation entre votre nouvelle table utilisateur et webpages_UsersInRoles ou les anciennes vérifications d'intégrité référentielle vous briseront au moment de l'exécution. (Je vous recommande fortement de supprimer la table UserProfile existante et de vérifier qu'elle n'est pas recréée. Si c'est le cas, il vous reste quelque chose dans votre code).
18
Gone Coding

Ajoutez une nouvelle table à la base de données et appelez-la User_Details ou similaire, lors de la création d'un utilisateur, vous pouvez ensuite récupérer l'ID de l'utilisateur et forcer les détails dans la nouvelle table. Ceci est une option simple.

6
CR41G14

Jetez un œil au modèle de projet Internet MVC4 fourni avec VS2012 ou VS2010. Vous devez vous assurer que la base de données n'est pas créée avant de modifier les colonnes de votre classe userprofile. vous pouvez ajouter plus de propriétés dans vos classes POCO, puis régénérer votre base de données. si vous ajoutez des propriétés après la génération de la base de données, assurez-vous que vous utilisez les migrations EF pour ajouter ces nouvelles propriétés à la base de données

3
pranav rastogi

Bien sûr, vous savez probablement que vous devez rendre votre RegisterModel identique à UserProfile Model. Ce que j'aime faire, c'est utiliser Migrations avant d'initialiser la base de données et mettre ce qui suit dans le Configuration.cs fichier:

    protected override void Seed(UsersContext context)
    {

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

        if (!WebSecurity.UserExists("yardpenalty"))
            WebSecurity.CreateUserAndAccount(
                "yardpenalty",
                "password",
                new
                {
                    Email = "[email protected]",
                    ImageUrl = "/Content/Avatars/yourname",
                    DateJoined = DateTime.Now
                },
                false);  
           //... rest of model.Builder stuff 
   }

Ensuite, j'utilise le Packet Manager Console par ces trois commandes faciles à mémoriser:

  1. Enable-Migrations
  2. Add-Migration MigrationName
  3. Update-Database // sera issu de Configuration.cs

Je suis d'accord avec TrueBlueAussie , et j'irais jusqu'à dire que LazyInitialization n'est plus très utile et vous n'avez vraiment plus besoin de l'appeler comme vous l'avez fait. Quoi qu'il en soit, tout ce que vous avez à faire est de changer votre action d'enregistrement dans votre contrôleur de compte pour appeler la méthode comme ceci:

  WebSecurity.CreateUserAndAccount(model.UserName, model.Password, propertyValues: new { model.Email, model.ImageUrl, model.DateJoined });

REMARQUE: MVC5 utilise OWIN

3
yardpenalty