ASP.NET Identity报错:不支持同一类型多对象集,旧方案无效
问题场景
使用Entity Framework访问ASP.NET Identity的用户表,以ApplicationDbContext为数据库上下文,通过Visual Studio脚手架为ApplicationUser类生成新Controller后,出现运行时错误:
Multiple object sets per type are not supported. The object sets 'ApplicationUsers' and 'Users' can both contain instances of type 'MyApp.Models.ApplicationUser'
脚手架生成过程中,会自动向ApplicationDbContext类添加如下代码:
public System.Data.Entity.DbSet<MyApp.Models.ApplicationUser> ApplicationUsers { get; set; }
由于ApplicationDbContext继承的IdentityDbContext本身已包含一个ApplicationUser类型的DbSet<ApplicationUser> Users,导致类型冲突。但直接删除上述自动生成的代码会引发编译错误——因为新增的Controller中直接使用了ApplicationUsers属性:
namespace MyApp.Controllers { public class NewController : Controller { private ApplicationDbContext db = new ApplicationDbContext(); // GET: Admin public ActionResult Index() { return View(db.ApplicationUsers.ToList()); } } }
修改属性或ApplicationUser类名也无法解决问题,现需寻找无需删除自动生成代码的修复方案。
修复方案
无需删除ApplicationUsers属性,只需在ApplicationDbContext的构造函数中,将该属性指向IdentityDbContext自带的Users集合,让两个属性引用同一个DbSet实例即可:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser> { public ApplicationDbContext() : base("DefaultConnection", throwIfV1Schema: false) { // 将自动生成的ApplicationUsers指向Identity原生的Users集合 ApplicationUsers = base.Users; } // 保留脚手架自动生成的这行代码 public System.Data.Entity.DbSet<MyApp.Models.ApplicationUser> ApplicationUsers { get; set; } // 其他自定义DbSet... }
原理说明
EF会检测同一类型的多个DbSet实例并抛出冲突错误,通过让ApplicationUsers和Users指向同一个集合实例,EF会认为这是同一个对象集,从而避免冲突。同时Controller中的代码无需修改,可正常编译运行。
内容的提问来源于stack exchange,提问作者Martin Vaughan

