简体   繁体   English

实体框架代码优先问题(SimpleMembership UserProfile表)

[英]Entity Framework Code-First Issues (SimpleMembership UserProfile table)

If you've used ASP.NET MVC 4 you'll notice that the default for an Internet Application is to use the SimpleMembership provider, this is all well and good and works fine. 如果您使用过ASP.NET MVC 4,您会注意到Internet应用程序的默认设置是使用SimpleMembership提供程序,这一切都很好,并且工作正常。

The issue comes with the default database generation, they have a POCO for UserProfile defined like so: 问题是默认的数据库生成,他们有一个用于UserProfile的POCO定义如下:

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

.. which is then generated like this: ..然后生成如下:

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

This works fine, the database is generated just fine and works without issue. 这工作正常,数据库生成正常,工作没有问题。 However, if I am to change the POCO like this and delete the database: 但是,如果我要像这样更改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; }
}

Only the first 2 columns are generated, UserId and EmailAddress . 仅生成前2列, UserIdEmailAddress It works just fine code-wise (talking login/registration), but obviously none of my other user data is stored. 它工作得很好(代码登录/注册),但显然没有存储我的其他用户数据。

Am I missing something here? 我在这里错过了什么吗? Surely it should generate the database based off the whole UserProfile object. 当然它应该基于整个UserProfile对象生成数据库。

1 - You need to enable migrations, prefereably with EntityFramework 5. Use Enable-Migrations in the NuGet package manager. 1 - 您需要启用迁移,尤其是使用EntityFramework 5.在NuGet包管理器中使用Enable-Migrations

2 - Move your 2 - 移动你的

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

to your Seed method in your YourMvcApp/Migrations/Configuration.cs class 您的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"});
    }

Now EF5 will be in charge of creating your UserProfile table, after doing so you will call the WebSecurity.InitializeDatabaseConnection to only register SimpleMembershipProvider with the already created UserProfile table, also tellling SimpleMembershipProvider which column is the UserId and UserName. 现在EF5将负责创建您的UserProfile表,在这样做之后,您将调用WebSecurity.InitializeDatabaseConnection仅使用已创建的UserProfile表注册SimpleMembershipProvider,同时调用SimpleMembershipProvider哪个列是UserId和UserName。 I am also showing an example of how you can add Users, Roles and associating the two in your Seed method with custom UserProfile properties/fields eg a user's Mobile (number). 我还展示了一个示例,说明如何添加用户,角色并将Seed方法中的两者与自定义UserProfile属性/字段相关联,例如用户的Mobile(数字)。

3 - Now when you run update-database from Package Manager Console, EF5 will provision your table with all your custom properties 3 - 现在,当您从Package Manager控制台运行update-database时,EF5将为您的表配置所有自定义属性

For additional references please refer to this article with sourcecode: http://blog.longle.net/2012/09/25/seeding-users-and-roles-with-mvc4-simplemembershipprovider-simpleroleprovider-ef5-codefirst-and-custom-user-properties/ 有关其他参考资料,请参阅本文的源代码: http//blog.longle.net/2012/09/25/seeding-users-and-roles-with-mvc4-simplemembershipprovider-simpleroleprovider-ef5-codefirst-and-custom -user的属性/

It seems I may have finally got this, and it may have just been one giant misunderstanding. 看来我可能终于得到了这个,它可能只是一个巨大的误解。

As it turns out, I was expecting ((IObjectContextAdapter)context).ObjectContext.CreateDatabase(); 事实证明,我期待((IObjectContextAdapter)context).ObjectContext.CreateDatabase(); to do what it simply doesn't, which is create all of the tables in the database that don't exist, or simply update them if they do and they're different. 做它根本不做的事情,即创建数据库中不存在的所有表,或者只是更新它们并且它们不同。

What actually happens is that it literally runs a CREATE DATABASE statement, which to me is the most useless thing ever. 实际发生的是它实际上运行了一个CREATE DATABASE语句,这对我来说是最无用的东西。 Unless you're working in a really strange environment, you will always have a database on the off and so it would always exist (and subsequently the table creation would never happen!), I'd rather not be giving real-world users access to create a database anyway. 除非你在一个非常奇怪的环境中工作,否则你将永远拥有一个数据库,因此它将永远存在(随后表创建永远不会发生!),我宁愿不给真实世界的用户访问无论如何要创建一个数据库。

Anyway, I solved my specific issue of wanting UserProfile (and related tables) to create the database by using the DropCreateDatabaseIfModelChanges initializer, and forcing an initialization like below: 无论如何,我通过使用DropCreateDatabaseIfModelChanges初始化程序解决了我想要UserProfile (和相关表)创建数据库的特定问题,并强制进行如下初始化:

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

.. this works and is perfect for development but is pretty useless in practice since it will literally drop the database and recreate it from scratch if the model changes. ..这是有效的,非常适合开发,但在实践中相当无用,因为如果模型发生变化,它将从字面上删除数据库并从头开始重新创建它。 To me, this makes the whole code-first practice almost useless in it's default form and I'll probably end up reverting back to a from-DB edmx generation. 对我来说,这使得整个代码优先实践在它的默认形式中几乎无用,我可能最终会恢复到来自DB的edmx生成。

The "mystery" behind the UserProfile table still being created is that WebSecurity.InitializeDatabaseConnection will initialise the table if it doesn't exist based on the fields you pass into it, which is why the EmailAddress was created instead of UserName , because I had changed it in this. 仍然正在创建的UserProfile表背后的“神秘”是WebSecurity.InitializeDatabaseConnection将根据您传入其中的字段初始化表,这就是创建EmailAddress而不是UserName原因,因为我已经更改了它在这。

I was having the same issue. 我遇到了同样的问题。 I added code to for the migrations to happen just before the "CreateDatabase" in the SimpleMembershipInitializer. 我添加了代码,以便在SimpleMembershipInitializer中的“CreateDatabase”之前进行迁移。

That fixed the issue for me, except that I believe that now my migrations are going to be applied in Azure regardless the setting in the publishing profile. 这解决了我的问题,除了我相信现在我的迁移将在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
            {....

If you don't have plans to make changes once the system is live and this is only happening in development and not keen to enable migrations. 如果您没有计划在系统生效后进行更改,这只是在开发中发生而不是热衷于启用迁移。 Try to truncate the table __MigrationHistory. 尝试截断表__MigrationHistory。

truncate table __MigrationHistory

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM