我真的无法弄清楚。我经常遇到此错误,并且不确定如何修改代码以支持1对多。到目前为止,我已阅读的示例很难理解。有些人建议修改流畅的API或模型,甚至修改控制器。
错误:
SqlException:当IDENTITY_INSERT设置为OFF时,无法为表'CompetitionCategory'中的标识列插入显式值。
System.Data.SqlClient.SqlCommand + <> c.b__122_0(任务结果)DbUpdateException:更新条目时发生错误。有关详细信息,请参见内部异常。
Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection连接,CancellationToken cancelledToken)
Competition
模型类:
public class Competition
{
[Key]
public int ID { get; set; }
[Required]
[Display(Name = "Competition Name")]
public string CompetitionName { get; set; }
[Required]
public string Status { get; set; }
public ICollection<CompetitionCategory> CompetitionCategories { get; set; }
}
CompetitionCategory
模型类:
public class CompetitionCategory
{
[Key]
public int ID { get; set; }
[Required]
[Display(Name = "Category Name")]
public string CategoryName { get; set; }
[ForeignKey("CompetitionID")]
public int CompetitionID { get; set; }
}
经过一番修补,我意识到将列表传递给控制器,我应该使用如下所示的视图模型:
public class CategoriesViewModelIEnumerable
{
public Competition competition { get; set; }
public CompetitionCategory competitionCategory { get; set; }
// From Microsoft
public IEnumerable<string> SelectedCategories { get; set; }
public List<SelectListItem> CategoriesList { get; } = new List<SelectListItem>
{
new SelectListItem { Value = "xxx", Text = "xxx" },
new SelectListItem { Value = "yyy", Text = "yyy" },
new SelectListItem { Value = "zzz", Text = "zzz" },
};
}
我可以成功地将数据传递到控制器并在控制台上读取/打印。但是,我遇到的最后一个错误是可能将第二个类别再保存到数据库中,这可能是由于某些主键/外键限制所致。
我目前只能将列表中的第一项保存到数据库中。
public async Task<IActionResult> Create(CategoriesViewModelIEnumerable model)
{
if (ModelState.IsValid)
{
CompetitionCategory competitionCategory = new CompetitionCategory();
_context.Add(model.competition);
await _context.SaveChangesAsync();
foreach (var CategoryName in model.SelectedCategories)
{
competitionCategory.CategoryName = CategoryName;
competitionCategory.CompetitionID = model.competition.ID;
_context.Add(competitionCategory);
await _context.SaveChangesAsync();
}
await _context.SaveChangesAsync();
}
}
非常感谢您的帮助! :)
答案 0 :(得分:2)
好吧,我可能会看到2个问题。
您应该先创建完整的模型,然后添加它,在这种情况下,第二个添加应该是更新,因为您已经添加了第一个并保存了更改,因此创建模型会更好。完全包含所有数据并添加它,然后保存更改。
CompetitionCategory competitionCategory = new CompetitionCategory();
foreach (var CategoryName in model.SelectedCategories)
{
competitionCategory.CategoryName = CategoryName;
competitionCategory.CompetitionID = model.competition.ID;
}
_context.Add(model.competition);
await _context.SaveChangesAsync();
答案 1 :(得分:0)
编辑:如果不清楚,可以使用此答案
非常感谢Kelso Sharp向我指出正确的方向。通过编辑控制器对其进行了修复。
供其他用户参考:
基本上,您只需要添加“主模型”,在本例中为Competition
。
由于Competition
已经具有CompetitionCategory
的集合,请对其进行初始化,然后将每个CompetitionCategory
添加到该集合中,如for循环所示。
最后,将模型Competition
添加到数据库中。我假设EF Core将在完成外键映射后自动将Collection数据添加到CompetitionCategory
表中。 (如果有误,请编辑此内容)
工作控制器:
public async Task<IActionResult> Create(CategoriesViewModelIEnumerable model)
{
if (ModelState.IsValid)
{
model.competition.CompetitionCategories = new Collection<CompetitionCategory>();
foreach (var CategoryName in model.SelectedCategories)
{
model.competition.CompetitionCategories.Add(new CompetitionCategory { CompetitionID=model.competition.ID, CategoryName=CategoryName});
}
_context.Add(model.competition);
await _context.SaveChangesAsync();
}
}
答案 2 :(得分:0)
我认为问题(尚未进行实际测试)是,您实例化了CompetitionCategory实体一次,然后尝试在foreach循环中的每次迭代中将单个实例添加到模型中。
您应该为每次迭代创建一个新的CompetitionCategory实例,然后将每个新实体添加到模型中:
foreach (var CategoryName in model.SelectedCategories)
{
CompetitionCategory competitionCategory = new CompetitionCategory();
competitionCategory.CategoryName = CategoryName;
competitionCategory.CompetitionID = model.competition.ID;
_context.Add(competitionCategory);
}
await _context.SaveChangesAsync();
答案 3 :(得分:0)
要解决该错误,您可以考虑将显式id存储到外键中,但是EF Core在标识插入设置为on的表上设置了主键。要显式关闭它,请在您的DbContext中重写OnModelCreating方法(如果尚未这样做),并在此行中输入:
protected override OnModelCreating(DbModelBuilder modelBuilder){
//some more code if necessary - define via Fluent api below
modelBuilder.Entity<CompetitionCategory>().Property(t => t.CompetitionID)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
//define also other ids to not have databasegeneration option set to identity to allow explicit idsif required
}
您也可以考虑先将Competition和CompetitionCategory保存在事务中,以便可以使用EF中的TransactionScope回滚或提交事务(无论是否遇到错误)。无论如何,您得到的错误是由于您设置了明确的ID,如果没有明确说明,EF默认将设置ID列并插入标识。如果更方便,则可以使用databasegeneratedoption属性。参见DatabaseGeneratedOption attribute