Entity Framework 6 和 Asp.Net Identity UserManager:多个 DbContext

Entity Framework 6 and Asp.Net Identity UserManager: Multiple DbContext(Entity Framework 6 和 Asp.Net Identity UserManager:多个 DbContext)
本文介绍了Entity Framework 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).

这篇关于Entity Framework 6 和 Asp.Net Identity UserManager:多个 DbContext的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本站部分内容来源互联网,如果有图片或者内容侵犯您的权益请联系我们删除!

相关文档推荐

DispatcherQueue null when trying to update Ui property in ViewModel(尝试更新ViewModel中的Ui属性时DispatcherQueue为空)
Drawing over all windows on multiple monitors(在多个监视器上绘制所有窗口)
Programmatically show the desktop(以编程方式显示桌面)
c# Generic Setlt;Tgt; implementation to access objects by type(按类型访问对象的C#泛型集实现)
InvalidOperationException When using Context Injection in ASP.Net Core(在ASP.NET核心中使用上下文注入时发生InvalidOperationException)
LINQ many-to-many relationship, how to write a correct WHERE clause?(LINQ多对多关系,如何写一个正确的WHERE子句?)