2016-04-11 3 views
0

私はASP.NET 5、MVC6、EF7を使って言語の文法を収集しています。文法は多くのタグを持つことができます(タグはレベル、意味など)、1つのタグは多くの文法で使用できます。前に追加された既存のタグを使用してタグシステムを実装する

文法を追加してタグを付けたら、文法を追加するたびに新しいタグを追加するのではなく、既存のタグ(最初に追加されたタグ)を文法から指摘したいユーザーがSOのようにタグを入力するとき)。

これらは私が使用しているモデルとコンテキストです。http://docs.efproject.net/en/latest/modeling/relationships.html#many-to-manyからの読み取りによって多対多を実装しました。 ApplicationDbContextで

public class Tag 
{ 
    public int TagId { get; set; } 
    [Required] 
    public string Text { get; set; } 
    public List<GrammarTag> GrammarTags { get; set; } 
} 

public class Grammar 
{ 
    public int GrammarId { get; set; } 
    public List<GrammarTag> GrammarTags { get; set; } 
     .... 
} 

public class GrammarTag 
{ 
    public int TagId { get; set; } 
    public Tag Tag { get; set; } 
    public int GrammarId { get; set; } 
    public Grammar Grammar { get; set; } 
} 

そしてOnModelCreating

protected override void OnModelCreating(ModelBuilder builder) 
    { 
     base.OnModelCreating(builder); 

     builder.Entity<GrammarTag>().HasKey(g => new { g.GrammarId, g.TagId }); 

     builder.Entity<Tag>() 
      .HasMany(t => t.GrammarTags) 
      .WithOne() 
      .OnDelete(Microsoft.Data.Entity.Metadata.DeleteBehavior.Cascade); 

     builder.Entity<Grammar>() 
      .HasMany(g => g.GrammarTags) 
      .WithOne() 
      .OnDelete(Microsoft.Data.Entity.Metadata.DeleteBehavior.Cascade); 

     builder.Entity<GrammarTag>() 
      .HasOne(gt => gt.Grammar) 
      .WithMany(g => g.GrammarTags) 
      .HasForeignKey(gt => gt.GrammarId); 

     builder.Entity<GrammarTag>() 
      .HasOne(gt => gt.Tag) 
      .WithMany(t => t.GrammarTags) 
      .HasForeignKey(gt => gt.TagId); 

    } 

でコントローラにメソッドを作成し、私が前に追加されたのと同じタグを使用して文法を追加するときに問題がある

public async Task<IActionResult> Create(AddGrammarViewModel viewmodel) 
    { 
     if (ModelState.IsValid) 
     { 
      if (!User.IsSignedIn()) 
      { 
       return RedirectToAction("Index", "Account"); 
      } 

      var grammar = new Grammar() 
      { 
       .... 
      }; 
      // in viewmodel, Tag is string and is delimited each Tag by comma 
      var tags = viewmodel.Tags.Split(','); 
      var tagList = new List<Tag>(); 

      foreach (var tag in tags) 
      { 
       if (_context.Tag.Any(t => t.Text == tag)) 
       { 
        tagList.Add(_context.Tag.Single(t => t.Text == tag)); 
       } 
       else 
       { 
        tagList.Add(new Tag { Text = tag }); 
       } 
      } 

      var grammaTagList = new List<GrammarTag>(); 

      foreach (var tag in tagList) 
      { 
       grammaTagList.Add(new GrammarTag { Tag = tag, Grammar = grammar }); 
      } 

      _context.Grammar.Add(grammar); 
      _context.Tag.AddRange(tagList); 
      _context.GrammarTag.AddRange(grammaTagList); 
      await _context.SaveChangesAsync(); 

      return RedirectToAction("Index"); 
     } 
     return View(viewmodel); 
    } 

は、私はデータベースのエラーを得ましたSqlException: Cannot insert explicit value for identity column in table 'Tag' when IDENTITY_INSERT is set to OFF.
データベースからのクエリーと同じタグを使用していますが、これは私が望むやり方であるため、このタグシステムをどのように実装できるのか分かりません。

+1

既にデータベースに作成されたタグを再挿入しようとしているようです。タグがすでに存在する場合は、タグをそのまま残すか(必要に応じて更新することもできます)。 IDを一意にする必要があるため、同じIDでもう一度試して追加するとエラーになります。 – Jonathan

+0

@ジョナサンどのように文法に関係を追加することができますか?既存のタグを新しい文法タグに置き、_context.Tagに新しいタグだけを追加できますか? – witoong623

+0

ここでやっていないペイロード(関係に関する追加データ)を含める場合は、関係(例:「GrammarTag」)に明示的なエンティティが必要です。暗黙的な結合表を使用するだけで、人生とコードが大幅に簡素化されます。つまり、 'Tag'はプロパティ' public virtual ICollection {get;}を持ちます。セット; } 'と' Grammar'はプロパティ 'public virtual ICollection タグ{get;セット; } '。 EFはこれをネイティブに扱うことができ、流暢な設定が不要で、LINQのクエリはずっと簡単です。 –

答えて

0

最後に、データベースからクエリされたタグを挿入しているため、ID列(PK)があるため、エラーメッセージと同じ問題が発生していました。
そのタグが以前に追加されたかどうかを確認してから、新しいタグだけをデータベースに追加して、タグの結合テーブルとの関係を確認してから、それをGrammarTagに追加してから新しい文法タグをデータベースに追加するだけです。

var tags = viewmodel.Tags.Split(','); 
    // create old tag and new tag list 
    var oldTags = new List<Tag>(); 
    var newTags = new List<Tag>(); 

    // check old and new tag and add it to list 
    foreach (var tag in tags) 
    { 
     var testTag = await _context.Tag.FirstOrDefaultAsync(t => t.Text == tag); 

     if (testTag != null) 
     { 
      oldTags.Add(testTag); 
     } 
     else 
     { 
      newTags.Add(new Tag { Text = tag }); 
     } 
    } 

    var grammaTagList = new List<GrammarTag>(); 
    oldTags.AddRange(newTags); 

    // put every that in this Grammar to join table 
    foreach (var tag in oldTags) 
    { 
     grammaTagList.Add(new GrammarTag { Tag = tag, Grammar = grammar }); 
    } 

    _context.Grammar.Add(grammar); 
    // add only the new tag 
    _context.Tag.AddRange(newTags); 
    _context.GrammarTag.AddRange(grammaTagList); 
    await _context.SaveChangesAsync(); 
関連する問題