C# 实体框架代码优先问题(SimpleMembership UserProfile 表)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12502004/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Entity Framework Code-First Issues (SimpleMembership UserProfile table)
提问by Rudi Visser
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 UserProfiledefined like so:
问题来自于默认的数据库生成,他们有一个 POCOUserProfile定义如下:
[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, UserIdand EmailAddress. It works just fine code-wise (talking login/registration), but obviously none of my other user data is stored.
仅生成前 2 列,UserId并且EmailAddress. 它在代码方面工作得很好(谈论登录/注册),但显然我的其他用户数据都没有被存储。
Am I missing something here? Surely it should generate the database based off the whole UserProfileobject.
我在这里错过了什么吗?当然,它应该基于整个UserProfile对象生成数据库。
采纳答案by Rudi Visser
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();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.
事实证明,我期待((IObjectContextAdapter)context).ObjectContext.CreateDatabase();做它根本没有做的事情,即在数据库中创建所有不存在的表,或者如果它们存在并且它们不同则简单地更新它们。
What actually happens is that it literally runs a CREATE DATABASEstatement, which to me is the most useless thing ever. 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.
实际发生的是它实际上运行了一个CREATE DATABASE语句,这对我来说是最无用的东西。除非您在一个非常陌生的环境中工作,否则您将始终有一个数据库处于关闭状态,因此它会一直存在(随后表创建永远不会发生!),我宁愿不给真实世界的用户访问权限无论如何都要创建一个数据库。
Anyway, I solved my specific issue of wanting UserProfile(and related tables) to create the database by using the DropCreateDatabaseIfModelChangesinitializer, and forcing an initialization like below:
无论如何,我解决了我想要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);
}
}
.. 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.
.. 这有效并且非常适合开发,但在实践中非常无用,因为如果模型发生变化,它实际上会删除数据库并从头开始重新创建它。对我来说,这使得整个代码优先实践在默认形式下几乎毫无用处,我可能最终会恢复到 from-DB edmx 生成。
The "mystery" behind the UserProfiletable still being created is that WebSecurity.InitializeDatabaseConnectionwill initialise the table if it doesn't exist based on the fields you pass into it, which is why the EmailAddresswas created instead of UserName, because I had changed it in this.
UserProfile仍在创建的表背后的“奥秘”是,WebSecurity.InitializeDatabaseConnection如果表不存在,则会根据您传递给它的字段初始化该表,这就是为什么EmailAddress创建了而不是UserName,因为我已经在此更改了它。
回答by LeLong37
1 - You need to enable migrations, prefereably with EntityFramework 5. Use Enable-Migrationsin the NuGet package manager.
1 - 您需要启用迁移,最好使用 EntityFramework 5。Enable-Migrations在 NuGet 包管理器中使用。
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. 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 e.g. a user's Mobile (number).
现在 EF5 将负责创建您的 UserProfile 表,执行此操作后,您将调用 WebSecurity.InitializeDatabaseConnection 以仅向已创建的 UserProfile 表注册 SimpleMembershipProvider,同时告诉 SimpleMembershipProvider 哪一列是 UserId 和 UserName。我还展示了一个示例,说明如何在 Seed 方法中添加用户、角色并将两者与自定义 UserProfile 属性/字段(例如用户的手机(号码))相关联。
3 - Now when you run update-database from Package Manager Console, EF5 will provision your table with all your custom properties
3 - 现在,当您从包管理器控制台运行 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 -用户属性/
回答by rufo
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
{....
回答by Siva
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

