5

これは 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 - 良いなど) があり、ライブラリのようなものです。このテーブルには挿入したくありません。

私がやろうとしているのは、ユーザーがサイトに登録し、先に進むレベルを選択してDBから取得し、UserLevelsテーブルに newUserIDおよび selectedが入力されるようにすること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..

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

そこに既に存在するレベルをレベルテーブルに挿入しようとしていることに関係があると思いますか? もちろん、それは何か他のものかもしれません...何かアドバイスはありますか?前もって感謝します!

4

1 に答える 1

15

「箱から出してすぐに使える」方法を使用している場合UserManager、おそらく次のようにインスタンス化されます。

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>

また、ここで Dependency Injection をうまく活用してMyDbContext、DI コンテナーによってインスタンスを挿入し、現在のコードをほとんど変更せずに維持することもできます。

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

チュートリアル(Microsoft Unity 用) を参照してください。

于 2014-03-26T20:19:52.640 に答える