私は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.
。
データベースからのクエリーと同じタグを使用していますが、これは私が望むやり方であるため、このタグシステムをどのように実装できるのか分かりません。
既にデータベースに作成されたタグを再挿入しようとしているようです。タグがすでに存在する場合は、タグをそのまま残すか(必要に応じて更新することもできます)。 IDを一意にする必要があるため、同じIDでもう一度試して追加するとエラーになります。 – Jonathan
@ジョナサンどのように文法に関係を追加することができますか?既存のタグを新しい文法タグに置き、_context.Tagに新しいタグだけを追加できますか? – witoong623
ここでやっていないペイロード(関係に関する追加データ)を含める場合は、関係(例:「GrammarTag」)に明示的なエンティティが必要です。暗黙的な結合表を使用するだけで、人生とコードが大幅に簡素化されます。つまり、 'Tag'はプロパティ' public virtual ICollection {get;}を持ちます。セット; } 'と' Grammar'はプロパティ 'public virtual ICollection タグ{get;セット; } '。 EFはこれをネイティブに扱うことができ、流暢な設定が不要で、LINQのクエリはずっと簡単です。 –