ASP.NET实现仓储模式引发'IdentityUserLogin'无主键定义错误
这个问题的根源其实和仓储模式本身无关,而是你新创建的MeetContext没有包含ASP.NET Identity实体的配置,EF的自动发现机制把Identity相关实体纳入了这个上下文,才导致了缺少主键定义的错误。
为什么之前没问题?
在你没使用仓储模式时,控制器用的是ApplicationDbContext——它继承自IdentityDbContext<ApplicationUser>,这个上下文已经内置了所有Identity实体(比如IdentityUserLogin、IdentityUserRole等)的主键和关系配置,所以EF能正确识别这些实体。
但现在你换成了自己的MeetContext,它继承的是普通的DbContext,EF会自动扫描程序集中的所有实体类型(包括Identity的那些),但你的MeetContext没有对这些Identity实体做任何配置,因此就抛出了“没有键定义”的错误。
解决方案
方案1(推荐):让MeetContext继承自IdentityDbContext
如果你的Meet实体和Identity用户数据共享同一个数据库,直接让MeetContext继承IdentityDbContext即可,这样它会自动继承所有Identity实体的配置:
修改MeetContext.cs:
using System.Data.Entity; using MVCWebAssignment1.Models; using Microsoft.AspNet.Identity.EntityFramework; // 记得添加这个命名空间 namespace MVCWebAssignment1.DAL { public class MeetContext : IdentityDbContext<ApplicationUser> { public MeetContext() : base("name=DefaultConnection") {} public DbSet<Meet> Meets { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); // 必须调用基类方法,加载Identity的配置 } } }
这样MeetContext就拥有了Identity实体的所有映射规则,EF不会再报错,同时也能正常操作你的Meet实体。
方案2:让MeetContext忽略Identity实体
如果你不想让MeetContext关联Identity数据,可以在OnModelCreating方法中显式忽略所有Identity相关实体:
protected override void OnModelCreating(DbModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); // 忽略所有Identity实体 modelBuilder.Ignore<IdentityUserLogin>(); modelBuilder.Ignore<IdentityUserRole>(); modelBuilder.Ignore<IdentityUserClaim>(); modelBuilder.Ignore<IdentityRole>(); }
不过这种方式需要手动维护所有要忽略的Identity实体,后续如果Identity有更新可能会遗漏,所以只推荐在Meet实体和Identity完全隔离(比如用不同数据库)的场景下使用。
额外检查
确保MeetContext使用的连接字符串DefaultConnection和原来的ApplicationDbContext一致,这样数据库结构是兼容的,避免出现其他数据库层面的问题。
内容的提问来源于stack exchange,提问作者Nsomnic

