C# 使用之前添加的现有标记实现标记系统
我正在使用ASP.NET5、MVC6和EF7创建一个收集语言语法的网站,一个语法可以有许多标记(标记用于表示级别、含义等),一个标记可以用于许多语法 当我添加语法然后将标记附加到它时,我希望现有的标记(第一次添加的)从语法中指向,而不是每次添加语法时都添加新的标记(稍后我计划在用户以同样的方式键入标记时实现自动完成) 这些是我使用的模型和上下文,我通过读取实现了多对多C# 使用之前添加的现有标记实现标记系统,c#,asp.net,asp.net-mvc,entity-framework,C#,Asp.net,Asp.net Mvc,Entity Framework,我正在使用ASP.NET5、MVC6和EF7创建一个收集语言语法的网站,一个语法可以有许多标记(标记用于表示级别、含义等),一个标记可以用于许多语法 当我添加语法然后将标记附加到它时,我希望现有的标记(第一次添加的)从语法中指向,而不是每次添加语法时都添加新的标记(稍后我计划在用户以同样的方式键入标记时实现自动完成) 这些是我使用的模型和上下文,我通过读取实现了多对多 公共类标记 { public int TagId{get;set;} [必需] 公共字符串文本{get;set;} 公共列表文法
公共类标记
{
public int TagId{get;set;}
[必需]
公共字符串文本{get;set;}
公共列表文法标记{get;set;}
}
公共课语法
{
公共整数{get;set;}
公共列表文法标记{get;set;}
....
}
公共课语法课
{
public int TagId{get;set;}
公共标记{get;set;}
公共整数{get;set;}
公共语法{get;set;}
}
和在ApplicationDbContext中创建模型
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);
}
模型创建时受保护的覆盖无效(ModelBuilder)
{
基于模型创建(生成器);
builder.Entity().HasKey(g=>new{g.grammand,g.TagId});
builder.Entity()
.HasMany(t=>t.GrammarTags)
.WithOne()
.OnDelete(Microsoft.Data.Entity.Metadata.DeleteBehavior.Cascade);
builder.Entity()
.HasMany(g=>g.GrammarTags)
.WithOne()
.OnDelete(Microsoft.Data.Entity.Metadata.DeleteBehavior.Cascade);
builder.Entity()
.HasOne(gt=>gt.Grammar)
.WithMany(g=>g.GrammarTags)
.HasForeignKey(gt=>gt.grammand);
builder.Entity()
.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);
}
公共异步任务创建(AddGrammarViewModel viewmodel)
{
if(ModelState.IsValid)
{
如果(!User.IsSignedIn())
{
返回重定向操作(“索引”、“帐户”);
}
var grammar=新语法()
{
....
};
//在viewmodel中,标记是字符串,每个标记用逗号分隔
var tags=viewmodel.tags.Split(',');
var tagList=新列表();
foreach(标签中的var标签)
{
if(_context.Tag.Any(t=>t.Text==Tag))
{
tagList.Add(_context.Tag.Single(t=>t.Text==Tag));
}
其他的
{
添加(新标记{Text=Tag});
}
}
var grammaTagList=新列表();
foreach(标记列表中的var标记)
{
Add(新的GrammarTag{Tag=Tag,Grammar=Grammar});
}
_context.Grammar.Add(语法);
_context.Tag.AddRange(标记列表);
_context.GrammarTag.AddRange(grammaTagList);
wait_context.SaveChangesAsync();
返回操作(“索引”);
}
返回视图(viewmodel);
}
问题是,当我添加使用以前添加的相同标记的语法时,出现数据库错误SqlException:当identity\u insert设置为OFF时,无法在表“Tag”中插入identity列的显式值。
我认为这是因为我使用的标签与从数据库查询的标签相同,但这是我想要的方式,所以我不知道如何实现这个标签系统。最后,我发现了问题,正如错误消息所说,这是因为我插入了从数据库查询的标签,因此它具有标识列(PK)。
所以,我只需检查该标记之前是否已添加,然后只向数据库添加新标记,对于标记与联接表的关系,我只需将其添加到GrammarTag,然后将所有新的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();
var-tags=viewmodel.tags.Split(',');
//创建旧标记和新标记列表
var oldTags=新列表();
var newTags=新列表();
//检查新旧标签并将其添加到列表中
foreach(标签中的var标签)
{
var testTag=await_context.Tag.FirstOrDefaultAsync(t=>t.Text==Tag);
if(testTag!=null)
{
添加(testTag);
}
其他的
{
Add(新标记{Text=Tag});
}
}
var grammaTagList=新列表();
oldTags.AddRange(newTags);
//把这个语法中的每一个都放到联接表中
foreach(oldTags中的var标记)
{
Add(新的GrammarTag{Tag=Tag,Grammar=Grammar});
}
_context.Grammar.Add(语法);
//仅添加新标记
_context.Tag.AddRange(newTags);
_context.GrammarTag.AddRange(grammaTagList);
wait_context.SaveChangesAsync();
听起来好像您正在尝试重新插入已创建到数据库中的标记。如果标签已经存在,您应该保留它(或者根据需要更新它)。如果您使用相同的ID再次尝试添加它,它将出错,因为ID必须是唯一的。@Jonathan那么我如何才能将其关系添加到语法中,我可以将现有的标记添加到新的GrammarTag中,并仅将新标记添加到_context.Tag中吗?如果您包含有效负载,则只需要为关系添加一个显式实体(即GrammarTag
)(关于关系的附加数据),您不在此处执行此操作。如果只使用隐式联接表,您的生活和代码将大大简化。换句话说,Tag
将具有属性public virtual ICollection{get;set;}
和Grammar
将有一个属性公共虚拟ICollection标记{get;set;}
。EF可以以本机方式处理此问题,因此不需要fluen
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();