i have problem that i cant solve. This is the scenario. i have two models, the 1st one is Question and the 2nd one is Answer. Also, i have DAL, BusinessEntities(view model) and BusinessServices class libraries with UnitOfWork and GenericRepository pattern. Problem is related to Edit action in that way when i edit(update) one model at the time it works but when i try to update Question model that has 3 Answers as list property i get this exception
//exception start Attaching an entity of type 'Quiz.DAL.Answer' failed because another entity of the same type already has the same primary key value. This can happen when using the 'Attach' method or setting the state of an entity to 'Unchanged' or 'Modified' if any entities in the graph have conflicting key values. This may be because some entities are new and have not yet received database-generated key values. In this case use the 'Add' method or the 'Added' entity state to track the graph and then set the state of non-new entities to 'Unchanged' or 'Modified' as appropriate. //exception end
exception occurs in GenericRepository class.
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;
}
}
ive checked if all data is posted from view to action and it is.
This is the method which is called from Edit action
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();
}
edit view
@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>
}
editor template for answerEntity
<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>
and finally the action method
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "Id,Name,Answers")]
QuestionEntity questionEntity)
{
if (ModelState.IsValid)
{
//db.Entry(questionEntity).State = EntityState.Modified;
//db.SaveChanges();
_questionServices.UpdateQuestion(questionEntity);
return RedirectToAction("Index");
}
return View(questionEntity);
}
i believe this error is popping cuz i have to tell ef that i wanna update answers but ef thinks they are new and that they should be created not updated witch leads to the same primary key error or, i have more then one copy of answer in memory and that confuses ef.
any help is appreciated.
EDIT https://github.com/StefanIvovic/Quiz check it out
answersDblist contains items with duplicateId. In general you should detect the new/deleted/updated items and call the correspondingAnswerRepositorymethods. - Ivan Stoev