2017-12-31 91 views
0

私はMVC5 Web Appをビルドします。私はIdentity Frameworkを使用しました。私はそれを作るようにしようとしているので、各ユーザには彼が関連している軍隊のリストがあります。これらはチェックボックスでページ上で更新されます。MVC5 - ManytoMany ApplicationUserを使用する既存のものを使用せずに新しい行を追加するか、エラーを投げる

私はこの拡張プロパティを持つデフォルトのApplicationUserクラスを拡張しました。

public virtual ICollection<Army> Armies { get; set; } 

    public ApplicationUser() 
    { 
     Armies = new HashSet<Army>(); 
    } 

また、これらのフィールドには陸軍クラスもあります。陸軍のテーブルには、異なる軍隊の詳細を記した約10の記入項目が入っています。

public class Army 
{ 
    public int Id { get; set; } 
    public String Name { get; set; } 
    public String IconLocation { get; set; } 
    public virtual ICollection<ApplicationUser> Users { get; set; } 

    public Army() 
    { 
     Users = new HashSet<ApplicationUser>(); 
    } 
} 

それから私は、ユーザーがユーザーの管理ページでこれらを編集することができDbContext

  protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     base.OnModelCreating(modelBuilder); 

     modelBuilder 
      .Entity<ApplicationUser>() 
      .HasMany(u => u.Armies) 
      .WithMany(t => t.Users) 
      .Map(m => 
      { 
       m.ToTable("UserArmies"); 
       m.MapLeftKey("UserId"); 
       m.MapRightKey("ArmyId"); 
      }); 

}

関係を設定して、これらは、チェックボックスの項目として表示されます。

public class CheckBoxItem 
{ 
    public int Id { get; set; } 
    public String Name { get; set; } 
    public bool IsChecked { get; set; } 
} 

コントローラは、軍隊をチェックボックスリストにするためにPopulateArmyCheckBoxList()メソッドを呼び出します。 (これはもともとリストを使って行われていましたが、私の問題を解決しようとしていた間に辞書を使って実装されています)プログラムのこの部分は期待どおりに機能し、チェックボックスをチェックしてください。

private List<CheckBoxItem> PopulateArmyCheckBoxList() 
    { 
     var userId = User.Identity.GetUserId(); 
     var userArmies = _context.Users.SingleOrDefault(u => u.Id == userId).Armies.ToDictionary(t=>t.Id, t=>t.Name); 

     var allArmies = _context.Armies.ToDictionary(t=>t.Id, t => t.Name); 
     var armyCheckBoxList = new List<CheckBoxItem>(); 


     foreach (var army in allArmies) 
     { 
      armyCheckBoxList.Add(new CheckBoxItem() 
      { 
       Id = army.Key, 
       Name = army.Value, 
       IsChecked = false 
      }); 
     } 

     foreach(var army in userArmies) 
     { 
      var cb = armyCheckBoxList.Find(c => c.Id == army.Key); 
      if(cb != null) 
       cb.IsChecked = true; 
     } 

     return armyCheckBoxList; 
    } 

viewModelには、Armiesと呼ばれるCheckBoxItemのUserとListが含まれています。初めてアクセスする場合は、User == nullとなり、viewModelにデータが設定されます。それ以外の場合は、データを受け取り、ユーザーを更新します。

public async Task<ActionResult> Index(IndexViewModel viewModel) 
    { 
     var userId = User.Identity.GetUserId(); 

     if (viewModel.User == null) 
     { 
      var model = new IndexViewModel 
      { 
       User = UserManager.FindById(userId), 
       Armies = PopulateArmyCheckBoxList() 
      }; 
      return View(model); 
     } 

     var user = UserManager.FindById(userId); 
     user.UserName = viewModel.User.UserName; 
     user.Email = viewModel.User.Email; 
     user.ProfilePictureLocation = SaveProfileImage(user, viewModel.ProfilePicture); 
     UserManager.Update(user); 

     ViewBag.StatusMessage = "Your Profile Has Been Updated."; 
     viewModel.User = UserManager.FindById(User.Identity.GetUserId()); 
     return View(viewModel); 
    } 

最後の段階はすべてがひどく間違っています。私はデータベース上のUserArmiesテーブルを更新する必要があります。 UserManager.Update(user)を呼び出す前に、次のコード行を追加してこれを実行しようとしました。

 user.Armies = GetUserArmies(user, viewModel.Armies); 

これは、次のメソッドを呼び出します。まず、Idのリストを取得し、selectedArmiesと呼んでください。私はデータベースから軍隊のリストを取り出し、それをallArmiesの中に入れます。 userArmiesは、記入して返す軍隊の空リストです。

private List<Army> GetUserArmies(ApplicationUser user, List<CheckBoxItem> armies) 
    { 
     var selectedArmies = armies.Where(a => a.IsChecked).Select(a => a.Id).ToList(); 
     var allArmies = _context.Armies.ToList(); 

     var userArmies = new List<Army>(); 

     foreach (var army in selectedArmies) 
      userArmies.Add(allArmies.Find(t => t.Id == army)); 

     return userArmies; 
    } 

2つの望ましくない結果がありました。最初は私が現在どのようになっているかです。 エラー軍のテーブルがどこにあるか私が代わりに次のような結果を得る私は陸軍クラスから仮想キーワードを削除すると、それらが異なるのObjectContextに添付されているために定義することができない2つのオブジェクト間の関係が

オブジェクト を言って起こります最初に新しいイドの下で陸軍の列を複製する。そして、新しいUserArmyはExsiting Armyの新しく作成された複製のもとでデータベースに保存されます。これにより、チェックボックスのリストが2倍になります。

どこが間違っていますか?どんな助けもありがとう。

追加情報 私は同じアーティクルテーブルを使用するユーザー記事クラスもあります。これは非常に似通ったコードを使用し、重複を作成せずに完全に動作します。これにより、UserManagerと_Contextを歌うことができます。

答えて

0

独自のDbContextを作成し、OnModelCreatingメソッドをオーバーライドする必要があります。

public class MyDbContext : DbContext 
{ 
    public MyDbContext() : base("YourDefaultConnectionString") 
    {   
     // Database Initializer 
    } 
    protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     // Write your own model creation code; 
    } 
} 

これはあなたにアイデアを提供します。

+0

提供された元のコードに示されているように私はすでにこれを行っていますか?ここで私はFluent APIを使って私の関係を洗練させましたか?メソッドをより明確にオーバーライドしていることを示すために投稿を変更します。他に何かがあれば、あなたはさらにヒントをつけることができますか? –

0

私はそれが私はデータをconbineすることができませんでした何らかの理由で、データにアクセスするためのUserManagerと_context(私自身のDbContext)を使用していた答え

を発見したと思います。 UserManagerの代わりに私のDBContextを介してユーザーを呼び出すために私のメソッドを交換することによって、私はエラーが発生し、問題を解決することができました。

関連する問題