[英]MVC5 EF6 Seed Method: Cannot insert NULL into column 'Id' table AspNetUsers
Entity Framework 6, MVC5, ASP Identity 2.0. 实体框架6,MVC5,ASP Identity 2.0。
I have followed this 2 tutorials to create the login part of the web application: part 1 - part 2 我已经按照这2个教程创建了Web应用程序的登录部分: 第1 部分 - 第2部分
I created my own AppUser class from IdentityUser Class in another library project. 我在另一个库项目中从IdentityUser类创建了自己的AppUser类。 I also have my data context from the IdentityDbContext 我也有来自IdentityDbContext的数据上下文
public class DataContext: IdentityDbContext<AppUser>
{
public DataContext(): base("DefaultConnection") { }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<AppUser>().Property(u => u.Id).HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity);
base.OnModelCreating(modelBuilder);
}
}
public class AppUser : IdentityUser
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public override string Id { get; set; }
[Required]
[Display(Name ="First Name")]
[MaxLength(100)]
public string FirstName { get; set; }
[Required]
[Display(Name = "Last Name")]
[MaxLength(100)]
public string LastName { get; set; }
[MaxLength(100)]
public string Title { get; set; }
[Required(ErrorMessage = "Email is required.")]
[Display(Description = "Email")]
public override string Email { get; set; }
[MaxLength(20)]
public string Phone { get; set; }
[Range(0,9999)]
[Display(Name = "Extension")]
public int PhoneExtension { get; set; }
[Display(Name = "Active")]
[DefaultValue(true)]
public bool IsActive { get; set; }
}
When I run the seed method I get the following error 当我运行种子方法时,出现以下错误
System.Data.SqlClient.SqlException: Cannot insert the value NULL into column 'Id', table 'CRM1.dbo.AspNetUsers'; System.Data.SqlClient.SqlException:无法将值NULL插入表'CRM1.dbo.AspNetUsers'的列'Id'中; column does not allow nulls. 列不允许为空。 INSERT fails. INSERT失败。 The statement has been terminated. 该语句已终止。
Here is the seeding method: 这是播种方法:
protected override void Seed(CRM.DAL.Data.DataContext context)
{
context.AccessLevels.AddOrUpdate(al => al.Label,
new Model.AccessLevel { AccessLevelID = 1, Label = "Admin", Description = "Full access to the CRM data" },
new Model.AccessLevel { AccessLevelID = 2, Label = "Customer Service", Description = "Full access to the CRM data" },
new Model.AccessLevel { AccessLevelID = 3, Label = "Sales", Description = "Full access to the CRM data" }
);
if (!(context.Users.Any(u => u.UserName == "admin@admin.com")))
{
var userStore = new UserStore<AppUser>(context);
var userManager = new UserManager<AppUser>(userStore);
var userToInsert = new AppUser
{
Id = "1",
FirstName = "Admin",
LastName = "Admin",
Title = "Administrator",
Email = "admin@admin.com",
PhoneExtension = 0,
IsActive = true,
AccessLevelID = 1,
EmailConfirmed = true,
PhoneNumberConfirmed = true,
TwoFactorEnabled = false,
LockoutEnabled = false,
AccessFailedCount = 0,
UserName = "admin"
};
userManager.Create(userToInsert, "password");
}
}
So Id gets a value but EF says it is inserting NULL. 因此,Id获得了一个值,但EF表示正在插入NULL。 I tried by not giving any value to Id thinking EF would do it automatically but no. 我尝试不给ID赋予任何价值,以为EF会自动执行此操作,但没有。
What is the approach to seed an AspNetUser with my context? 用我的上下文播种AspNetUser的方法是什么? I saw different tutorials but it does not apply to my extended AppUser class and DataContext. 我看到了不同的教程,但不适用于扩展的AppUser类和DataContext。
Thank you 谢谢
The following happened to me. 以下发生在我身上。 I followed this guide to change the Primary Key for Users in ASP.NET Identity from Guid to Int. 我按照本指南将ASP.NET Identity中的用户主键从Guid更改为Int。
https://docs.microsoft.com/en-us/aspnet/identity/overview/extensibility/change-primary-key-for-users-in-aspnet-identity https://docs.microsoft.com/en-us/aspnet/identity/overview/extensibility/change-primary-key-for-users-in-aspnet-identity
I had already made some migrations so EF tried to change the Id from nvarchar(128) to int. 我已经进行了一些迁移,因此EF尝试将Id从nvarchar(128)更改为int。 This worked but Identity Specification
never turned from No to Yes. 此方法有效,但是Identity Specification
从未从“否”变为“是”。 Solved it by removing all previous migrations, removing the database and then make a new migration for all the changes. 通过删除所有以前的迁移,删除数据库然后对所有更改进行新的迁移来解决该问题。 Since we were early in development this was not a problem to do. 由于我们还处于开发初期,因此这不是问题。
Remove this line from your code: 从您的代码中删除此行:
modelBuilder.Entity<AppUser>().Property(u => u.Id).HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity);
and also this part from your User
: 以及User
这一部分:
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public override string Id { get; set; }
You don't need to override this property, just use the parent's property (entity framework will map it). 您无需覆盖此属性,只需使用父级的属性(实体框架将其映射)。
Explanation: when you configure the Id
property like your did, you're telling entity framework the property value comes from database, so it totally ignores the value you passed to this property when inserting into database. 说明:当像配置配置Id
属性时,您是在告诉实体框架该属性值来自数据库,因此在插入数据库时它完全忽略了传递给该属性的值。
On the other hand, if your column inside your database table does not have a default value, it will fails, because entity framework is not providing a value for it. 另一方面,如果数据库表中的列没有默认值,则它将失败,因为实体框架没有为其提供值。
So you need to decide: either your table must have a default value, or you should remove that HasDatabaseGeneratedOption
option for that field. 因此,您需要确定:表必须具有默认值,或者应删除该字段的HasDatabaseGeneratedOption
选项。
The thing is that IdentityUser
uses a string
as key, which normally would be a Guid
. 问题是IdentityUser
使用string
作为键,通常是Guid
。 Since EF won't generate Id
for you automatically, and your column won't as well, you can create a constructor
to your User
do like this: 由于EF不会自动为您生成Id
,并且您的列也不会自动生成Id
,因此您可以为User
创建一个constructor
,如下所示:
public AppUser()
{
Id = Guid.NewGuid().ToString();
}
Whenever you create a new user, it will have a new Guid
as Id....when you read an existing user from your context, although your constructor will generate it when being instantiated by EF, EF will then load Id
value from your table over it (ignoring the one provided in constructor). 当你创建一个新用户,这将有一个新Guid
为ID ....当你阅读从上下文中的现有用户,虽然你的构造会产生它由EF被实例化时,EF将然后加载Id
从表中的值在它上面(忽略构造函数中提供的那个)。
This means the autogenerated Guid inside your constructor will be used only for new instances. 这意味着构造函数中自动生成的Guid将仅用于新实例。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.