我使用ASP.NET 5,MVC6和EF7创建收集语法语法的网站,一个语法可以有很多Tag(Tag用于表示类似水平,含义等)和一个标签可用于许多语法。
当我添加语法然后将Tag附加到它时,我希望从Grammar指向现有的标签(第一次添加),而不是每次添加语法时添加新标签(后来我计划实现自动完成时)用户输入标签的方式与SO)相同。
这些是我使用的模型和上下文,我通过从http://docs.efproject.net/en/latest/modeling/relationships.html#many-to-many读取实现了多对多。
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; }
}
和ApplicationDbContext中的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);
}
在控制器中的Create方法
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.
。
我之所以这么想,是因为我使用了与数据库查询相同的标签,但这是我想要的方式,所以我无法弄清楚如何实现这个标签系统。
答案 0 :(得分:0)
最后,我想通了,问题就像错误消息所说的那样,因为我插入了从数据库查询的标签,因此它有标识列(PK)。
所以,我只需检查之前是否添加了Tag,然后只添加新的Tags到数据库,对于Tag与join表的关系,我只需将它添加到GrammarTag然后将所有新的GrammarTags添加到数据库。
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();