我有问题,我无法解决。这就是场景。 我有两个模型,第一个是问题,第二个是答案。此外,我有DAL,BusinessEntities(视图模型)和BusinessServices类库与UnitOfWork和GenericRepository模式。 问题与编辑动作有关,当我编辑(更新)一个模型时它工作但当我尝试更新有3个答案作为列表属性的问题模型我得到这个例外
//异常开始 附加“Quiz.DAL.Answer”类型的实体失败,因为同一类型的另一个实体已具有相同的主键值。如果图中的任何实体具有冲突的键值,则在使用“附加”方法或将实体的状态设置为“未更改”或“已修改”时,可能会发生这种情况。这可能是因为某些实体是新的并且尚未收到数据库生成的键值。在这种情况下,使用“添加”方法或“已添加”实体状态来跟踪图形,然后根据需要将非新实体的状态设置为“未更改”或“已修改”。 //例外结束
GenericRepository类中发生异常。
if(BUILD_SHARED_LIBS)
install (
FILES "$<TARGET_PDB_FILE:${library}>"
DESTINATION "${GDCM_INSTALL_BIN_DIR}"
COMPONENT DebugDevel
CONFIGURATIONS Debug RelWithDebInfo
)
endif()
我已经检查过是否所有数据都是从一个视图发布到另一个动作的。
这是从编辑操作
调用的方法public class GenericRepository<TEntity> where TEntity : class
{
internal QuizContext Context;
internal DbSet<TEntity> DbSet;
/// <summary>
/// Public Constructor,initializes privately declared local variables.
/// </summary>
/// <param name="context"></param>
public GenericRepository(QuizContext context)
{
this.Context = context;
this.DbSet = context.Set<TEntity>();
}
public virtual void Update(TEntity entityToUpdate)
{
DbSet.Attach(entityToUpdate); //exception is invoked here
Context.Entry(entityToUpdate).State = EntityState.Modified;
}
}
编辑视图
public class QuestionServices : IQuestionServices
{
private UnitOfWork _unitOfWork;
public void UpdateQuestion(QuestionEntity questionEntity)
{
var questionDb = new Question
{
Id = questionEntity.Id,
Name = questionEntity.Name
};
var answersDb = _unitOfWork.AnswerRepository.GetMany(a =>
a.QuestionId == questionDb.Id).ToList();
foreach (var a in questionEntity.Answers)
{
answersDb.Add(new Answer()
{
Id = a.Id,
Name = a.Name,
IsTrue = a.IsTrue,
QuestionId = a.QuestionId,
Question = questionDb
});
}
unitOfWork.QuestionRepository.Update(questionDb);
foreach (var answer in answersDb)
{
_unitOfWork.AnswerRepository.Update(answer);
}
_unitOfWork.Save();
}
answerEntity的编辑器模板
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>QuestionEntity</h4>
<hr />
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
@Html.HiddenFor(model => model.Id)
<div class="form-group">
@Html.LabelFor(model => model.Name, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Name, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Name, "", new { @class = "text-danger" })
</div>
</div>
@for (int i=0; i<Model.Answers.Count; i++)
{
@Html.EditorFor(m=>m.Answers[i])
}
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
}
最后是动作方法
<div class="form-horizontal"/>
@Html.HiddenFor(model=>model.Id)
@Html.HiddenFor(model=>model.QuestionId)
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
<div class="form-group">
@Html.LabelFor(model => model.Name, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Name, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Name, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.IsTrue, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
<div class="checkbox">
@Html.EditorFor(model => model.IsTrue)
@Html.ValidationMessageFor(model => model.IsTrue, "", new { @class = "text-danger" })
</div>
</div>
</div>
我相信这个错误正在弹出因为我必须告诉我,我想更新答案,但是ef认为他们是新的,他们应该创建不更新女巫导致相同的主键错误,或者, 我在内存中有一个以上的答案副本,这让人感到困惑。
感谢任何帮助。
EDIT https://github.com/StefanIvovic/Quiz检查出来
答案 0 :(得分:2)
这根本没有任何违法行为,因为老实说,这可能不是你的错。那里有太多糟糕的信息。尽管如此,这段代码绝对是悲剧性的。你有三个主要问题。
Don't use Bind
。像往常一样。停下来。马上。昨天,如果可能的话。如果您需要排除发布的属性使用视图模型,它基本上只是一个专门为视图定制的类,它只包含视图所需的内容。在这种情况下,这看起来像:
public class QuestionViewModel
{
public string Name { get; set; }
public List<Answer> Answers { get; set; }
}
请注意:1)Id
不包括在内。您永远不会允许发布ID。 id应该来自URI,因为它是什么使它成为&#34;通用资源标识符&#34;。 2)Answer
同样应该在这里使用视图模型,所以你的属性应该最像是List<AnswerViewModel>
,但我并不想让你压得太多。
永远不会永远将帖子创建的任何内容直接保存到您的数据库中。这实际上是通过使用视图模型来解决的,因为您必须保存与发布内容不同的内容。但是,您应始终将发布数据映射到要保存的实体。这在进行编辑时更为重要,因为您应始终从数据库中提取实体,修改该实例,然后保存该实例。通过这种方式,即使您不使用视图模型,您仍然不需要Bind
,因为除非您明确允许,否则用户无法真正获取他们发布的任何内容以保存到数据库中,通过将已发布的属性映射到您要保存的实体属性。
最后,工作模式的存储库/单元与像Entity Framework这样的ORM完全是多余的。 EF实际上已经实现了这些模式:DbContext
是您的工作单元,每个DbSet
都是一个存储库。在此之上添加一个层除了混淆正在发生的事情之外什么也没做什么,从而使您的应用程序更难以维护。我听过一百万和一个借口为什么人们认为你仍然应该实施这些模式,但他们都被误导了(&#34;如果没有它,你就无法进行测试!&#34;错误.EF是100%可测试的。)或者通过不同的模式(例如Command Query Responsibility Segregation (CQRS)或Service Layer Pattern)更好地解决。