如果您使用过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; }
}
仅生成前两列,UserId
和EmailAddress
。它工作得很好(代码登录/注册),但显然我的其他用户数据都没有存储。
我在这里遗漏了什么吗?当然它应该基于整个UserProfile
对象生成数据库。
答案 0 :(得分:47)
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属性/字段相关联的示例,例如用户的手机(号码)。
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-properties/ 强>
答案 1 :(得分: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
的原因。创建了1}}而不是UserName
,因为我在此更改了它。
答案 2 :(得分: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
{....
答案 3 :(得分:0)
如果您没有计划在系统生效后进行更改,这只是在开发中发生而不是热衷于启用迁移。尝试截断表__MigrationHistory。
truncate table __MigrationHistory