实体框架6和Asp.Net Identity UserManager:多个DbContext

时间:2014-03-26 07:38:59

标签: c# asp.net-mvc-5 entity-framework-6 asp.net-identity-2

这是MVC 5 / EF6。所以我有以下课程:

public class User : IdentityUser
{
    public User()
    {
        Levels = new List<Level>();
    }

    [Required, MaxLength(200)]
    public string FirstName { get; set; }

    [Required, MaxLength(200)]
    public string LastName { get; set; }

    public virtual ICollection<Level> Levels { get; set; }
}

public class Level
{
    public int Id { get; set; }

    [Required]
    public string Name { get; set; }

    public virtual ICollection<User> Users { get; set; }
}

除了常规MVC5成员资格表外,它还创建了2个:LevelsUserLevels(带有User_Id和Level_Id列)。 Levels表有一个静态数据(即1 - 优秀,2 - 良好等),并且是一种库,我不想在此表中插入。

我想要做的是当用户在网站上注册并选择它将继续进行并从数据库中检索它以便UserLevels表填充新的UserID并选择{ {1}}。这是我的代码:

LevelID

它会在此行引发异常:Level level = DBContext.Levels.Where(s => s.Name == model.Level.Name).SingleOrDefault(); if (level == null) ModelState.AddModelError("", "Invalid Level."); if (ModelState.IsValid) { var user = new User() { UserName = model.UserName, FirstName = model.FirstName, LastName = model.LastName }; user.Levels.Add(level); var result = await UserManager.CreateAsync(user, model.Password); if (result.Succeeded) { await SignInAsync(user, isPersistent: false); return RedirectToAction("Index", "Home"); } else { AddErrors(result); } } return View(model);

An entity object cannot be referenced by multiple instances of IEntityChangeTracker..

我猜这与它试图在 Levels 表中插入已经存在的级别有关?当然它可能是别的......有什么建议吗?提前谢谢!

1 个答案:

答案 0 :(得分:14)

如果您正在使用UserManager方式,那么它就是开箱即用的&#39;然后它可能会像这样实例化:

public AccountController()
: this(new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new MyDbContext())))
{
}

public AccountController(UserManager<ApplicationUser> userManager)
{
    UserManager = userManager;
}

public UserManager<ApplicationUser> UserManager { get; private set; }

这意味着,如果您未向UserManager构造函数提供AccountController实例(此处可能就是这种情况),则新MyDbContext为为UserManager商店创建。

然而,你有另一个MyDbContext的实例,因为我可以在你的代码中从这一行推断:

Level level = DBContext.Levels.Where(s => s.Name == model.Level.Name).SingleOrDefault();

这意味着你必须让UserManager使用相同的上下文:

public AccountController() : this(null)
{
}

public AccountController(UserManager<User> userManager = null)
{
    DBContext = new MyDBContext();

    if (userManager == null)
        userManager = new UserManager<User>(new UserStore<User>(DBContext));

    UserManager = userManager;
}

public UserManager<User> UserManager { get; private set; }
public MyDBContext DBContext;

这样,您首先创建(仅)MyDbContext实例,然后将其传递给UserManager构造函数(作为IUserStore<User>)。

此外,您绝对可以在此处充分利用依赖注入,并通过DI容器为您注入MyDbContext实例并保持当前代码几乎不变:

public AccountController(MyDBContext context)
: this(new UserManager<User>(new UserStore<User>(context)))
{
    this.DBContext = context;
}

请参阅Tutorial(适用于Microsoft Unity)。