28

如果您使用过 ASP.NET MVC 4,您会注意到 Internet 应用程序的默认设置是使用 SimpleMembership 提供程序,这一切都很好,并且工作正常。

问题来自默认数据库生成,它们有一个 POCO 用于UserProfile定义如下:

[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 列,UserId并且EmailAddress. 它在代码方面工作得很好(谈论登录/注册),但显然我的其他用户数据都没有被存储。

我在这里错过了什么吗?当然,它应该基于整个UserProfile对象生成数据库。

4

4 回答 4

47

1 - 您需要启用迁移,最好使用 EntityFramework 5.Enable-Migrations在 NuGet 包管理器中使用。

2 - 移动你的

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

到 YourMvcApp/Migrations/Configuration.cs 类中的 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。我还展示了一个示例,说明如何在 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 -用户属性/

于 2012-09-28T17:31:32.477 回答
5

看来我可能终于明白了,这可能只是一个巨大的误解。

事实证明,我期待((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);
    }
}

.. 这很有效,非常适合开发,但在实践中却毫无用处,因为如果模型发生变化,它实际上会删除数据库并从头开始重新创建它。对我来说,这使得整个代码优先实践在它的默认形式下几乎毫无用处,我可能最终会恢复到从数据库生成的 edmx 生成。

UserProfile仍在创建的表背后的“谜团”是,WebSecurity.InitializeDatabaseConnection如果它不存在,它将根据您传递给它的字段来初始化表,这就是为什么EmailAddress创建了而不是创建了UserName,因为我在此更改了它。

于 2012-09-23T22:47:51.087 回答
2

我遇到了同样的问题。我为在 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
            {....
于 2012-10-21T23:39:29.637 回答
0

如果您没有计划在系统上线后进行更改,并且这仅发生在开发中并且不热衷于启用迁移。尝试截断表 __MigrationHistory。

truncate table __MigrationHistory
于 2013-07-04T06:49:41.327 回答