entity framework代码优先问题(SimpleMembership UserProfile表)
如果您使用过ASP.NET MVC 4,您会注意到Internet应用程序的默认设置是使用SimpleMembership提供程序,这一切都很好,并且工作正常。
问题来自于默认的数据库生成,他们为UserProfile
定义了一个POCO,如下所示:
[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
对象生成数据库。
1 – 您需要启用迁移,尤其是使用EntityFramework 5.在NuGet包管理器中使用Enable-Migrations
。
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以仅使用已创建的UserProfile表注册SimpleMembershipProvider,同时调用SimpleMembershipProvider哪个列是UserId和UserName。 我还展示了一个示例,说明如何添加用户,角色并将Seed方法中的两者与自定义UserProfile属性/字段相关联,例如用户的Mobile(数字)。
3 – 现在,当您从Package Manager控制台运行update-database时,EF5将为您的表配置所有自定义属性
有关其他参考资料,请参阅本文的源代码: http : //blog.longle.net/2012/09/25/seeding-users-and-roles-with-mvc4-simplemembershipprovider-simpleroleprovider-ef5-codefirst-and-custom -user的属性/
看来我可能终于得到了这个,它可能只是一个巨大的误解。
事实certificate,我期待((IObjectContextAdapter)context).ObjectContext.CreateDatabase();
做它根本不做的事情,即创建数据库中不存在的所有表,或者只是更新它们并且它们不同。
实际发生的是它实际上运行了一个CREATE DATABASE
语句,对我来说这是最无用的事情。 除非你在一个非常奇怪的环境中工作,否则你总会有一个关闭的数据库,因此它总是存在(随后表创建永远不会发生!),我宁愿不给现实世界的用户访问无论如何要创建一个数据库。
无论如何,我通过使用DropCreateDatabaseIfModelChanges
初始化程序解决了我想要UserProfile
(和相关表)创建数据库的特定问题,并强制进行如下初始化:
public SimpleMembershipInitializer() { #if DEBUG Database.SetInitializer(new DropCreateDatabaseIfModelChanges ()); #else Database.SetInitializer (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); } }
..这是有效的,非常适合开发,但在实践中相当无用,因为如果模型发生变化,它将从字面上删除数据库并从头开始重新创建它。 对我来说,这使得整个代码优先实践在它的默认forms中几乎无用,我可能最终会恢复到来自DB的edmx生成。
仍在创建的UserProfile
表背后的“神秘”是WebSecurity.InitializeDatabaseConnection
将根据您传入其中的字段初始化表,这就是创建EmailAddress
而不是UserName
原因,因为我已经更改了它在这。
我遇到了同样的问题。 我添加了代码,以便在SimpleMembershipInitializer中的“CreateDatabase”之前进行迁移。
这解决了我的问题,除了我相信现在我的迁移将在Azure中应用,无论发布配置文件中的设置如何。
private class SimpleMembershipInitializer { public SimpleMembershipInitializer() { Database.SetInitializer(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(); var context = new WomContext(); migrations.InitializeDatabase(context); try {....
如果您没有计划在系统生效后进行更改,这只是在开发中发生而不是热衷于启用迁移。 尝试截断表__MigrationHistory。
truncate table __MigrationHistory