实体框架 6 和 Asp.Net Identity UserManager:多个 DbContext [英] Entity Framework 6 and Asp.Net Identity UserManager: Multiple DbContext

查看:28
本文介绍了实体框架 6 和 Asp.Net Identity UserManager:多个 DbContext的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

This is MVC 5/ EF6. So I have the following classes:

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 - 好等),是一种库,我不想插入到这个表中.

In addition to regular MVC5 membership tables it creates 2 more: Levels and UserLevels (with User_Id and Level_Id columns). Levels table has a static data (i.e. 1 - Excellent, 2 - Good, etc) and is kind of a library, I don't want to insert in this table.

我想做的是当用户在网站上注册并选择它会继续的级别并从数据库中检索它以便 UserLevels 表填充新的 UserID 并选择 LevelID.这是我的代码:

What I'm trying to do is when user registers on the site and chooses the level it would go ahead and retrieve it from DB so that UserLevels table is populated with new UserID and selected LevelID. Here is my code:

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);

它在这一行抛出异常:一个实体对象不能被多个 IEntityChangeTracker 实例引用..

var result = await UserManager.CreateAsync(user, model.Password);

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

I'm guessing it has something to do with it trying to insert into Levels table the level that already exists in there? Of course it might be something else... Any advice? Thanks in advance!

推荐答案

如果您以开箱即用"的方式使用 UserManager,那么它可能会像这样实例化:

If you're using UserManager the way 'it came out of the box' then it's probably instantiated like this:

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; }

这意味着如果您不向 AccountController 构造函数提供 UserManager 实例(这里可能就是这种情况),一个新的 MyDbContext 是为 UserManager 存储创建的.

It means that if you don't provide a UserManager instance to the AccountController constructor (and it's probably the case here), a new MyDbContext is created for the UserManager store.

然而,您还有另一个 MyDbContext 实例,我可以从您代码中的这一行推断:

Yet, you have another instance of MyDbContext, as i can infer from this line in your code:

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

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

All it means is that you have to make your UserManager use the same context:

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).

This way, you're creating the (only) MyDbContext instance first, then passing it to the UserManager constructor (as the IUserStore<User>).

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

Also, you can definitely make a good use of Dependency Injection here and have the MyDbContext instance injected for you by a DI container and keeping your current code almost unchanged:

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

请参阅教程(适用于 Microsoft Unity).

See Tutorial (for Microsoft Unity).

这篇关于实体框架 6 和 Asp.Net Identity UserManager:多个 DbContext的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆