使用.NET Identity实现含关联表的用户注册遇错求助
首先,你遇到的Invalid column name ApplicationUser_Id错误,根源在于实体类型不匹配和导航属性关联配置错误,下面一步步帮你解决:
问题分析
你的AddressBook实体中定义的导航属性是virtual AspNetUser AspNetUser,但实际项目中使用的用户实体是继承自IdentityUser的ApplicationUser,并且ApplicationDbContext中注册的也是ApplicationUser映射到AspNetUsers表。EF无法将AddressBook的AspNetUser导航属性正确关联到ApplicationUser,因此会自动尝试生成一个额外的外键列ApplicationUser_Id,这就导致了报错。
另外,你在注册代码中手动给AddressBook.UserId赋值user.Id是无效的——因为在调用UserManager.CreateAsync之前,user.Id还没有被生成(Identity会在保存用户时自动生成Id)。
解决方案
1. 修正AddressBook的导航属性类型
把AddressBook中的AspNetUser导航属性改成ApplicationUser,匹配你实际使用的用户实体:
public partial class AddressBook { [Key] [Column(Order = 0)] public long AddressId { get; set; } [Key] [Column(Order = 1)] public string UserId { get; set; } public int? AddressTypeId { get; set; } public bool? IsDefault { get; set; } public string Firstname { get; set; } public string LastName { get; set; } public virtual Address Address { get; set; } // 替换为ApplicationUser类型 public virtual ApplicationUser ApplicationUser { get; set; } }
2. 调整ApplicationDbContext的映射配置
确保AddressBook与ApplicationUser的关联配置正确,替换原来的AspNetUser关联配置:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser> { public ApplicationDbContext() : base("DefaultConnectionString") { } public static ApplicationDbContext Create() { return new ApplicationDbContext(); } // 别忘了添加Address和AddressBook的DbSet public DbSet<Address> Addresses { get; set; } public DbSet<AddressBook> AddressBooks { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); // 配置ApplicationUser映射到AspNetUsers表(这行其实可以省略,因为Identity默认就是这个表) modelBuilder.Entity<ApplicationUser>().ToTable("AspNetUsers"); // 配置Address实体主键 modelBuilder.Entity<Address>().HasKey(k => k.AddressId); // 配置AddressBook的复合主键 modelBuilder.Entity<AddressBook>().HasKey(k => new { k.UserId, k.AddressId }); // 关联AddressBook和Address modelBuilder.Entity<AddressBook>() .HasRequired(t => t.Address) .WithMany(t => t.AddressBooks) .HasForeignKey(t => t.AddressId) .WillCascadeOnDelete(false); // 根据业务需求决定是否级联删除 // 关联AddressBook和ApplicationUser(关键修正) modelBuilder.Entity<AddressBook>() .HasRequired(t => t.ApplicationUser) .WithMany(t => t.AddressBooks) .HasForeignKey(t => t.UserId) .WillCascadeOnDelete(true); // 用户删除时自动删除关联的地址簿记录 } }
注意:一定要在
ApplicationDbContext中添加Addresses和AddressBooks的DbSet,否则EF可能无法正确跟踪这些实体。
3. 修正注册代码中的关联逻辑
移除手动赋值UserId的代码,让EF通过导航属性自动处理外键关联:
var user = new ApplicationUser() { UserName = "NewUser5", Email = "a9@snapon.com" }; var addr = new Address { Address1 = "5505", City = "City A", Zip = "91334" }; var addressBook = new AddressBook() { Address = addr, Firstname = "ContactFName", LastName = "ConatactLName", AddressTypeId = 1, IsDefault = true }; user.AddressBooks.Add(addressBook); // 创建用户 IdentityResult result = await UserManager.CreateAsync(user, password); // 确保关联实体被保存(如果UserManager没有自动处理级联添加) if (result.Succeeded) { using (var db = ApplicationDbContext.Create()) { db.Entry(addr).State = EntityState.Added; db.Entry(addressBook).State = EntityState.Added; await db.SaveChangesAsync(); } }
为什么这样能解决问题?
- 修正导航属性类型后,EF能够正确识别
AddressBook与ApplicationUser的关联关系,不会再生成多余的ApplicationUser_Id列。 - 移除手动赋值
UserId的操作,让EF在保存用户时自动填充AddressBook.UserId的值,避免了空值或无效值的问题。 - 添加
DbSet并修正映射配置,确保EF能够正确跟踪和保存Address和AddressBook实体。
内容的提问来源于stack exchange,提问作者user3344235

