I didn't find any relevant answer here so I will trigger you, thanks in advance :
I have a controller with 2 methods of the Edit action, (I simplified it for better understanding):
MrSaleBeta01.Controllers
{
public class PostsController : Controller
{
private MrSaleDB db = new MrSaleDB();
...
// GET: Posts/Edit/5
public ActionResult Edit(int? id)
{
...
}
// POST: Posts/Edit/5
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit( Post post, int? CategoryIdLevel1, int? CategoryIdLevel2, int? originalCategoryId)
{
...
Category cnew = db.Categories.Find(post.CategoryId);
MoveFromCategory(post, originalCategoryId);
...
db.Entry(post).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
//move post from his old category (fromCategoryId) to a new one (post.CategoryId):
//returns true on success, false on failure.
public bool MoveFromCategory(Post post, int? fromCategoryId)
{
try
{
if (post.CategoryId == fromCategoryId)
return true;
Category cold = null, cnew = null;
if (fromCategoryId!=null)
cold = db.Categories.Find(fromCategoryId);
if (post.CategoryId != 0)
cnew = db.Categories.Find(post.CategoryId);
if (cold != null)
{
cold.Posts.Remove(post);
}
if( cnew != null)
cnew.Posts.Add(post);
db.Entry(cold).State = EntityState.Modified;
db.Entry(cnew).State = EntityState.Modified;
//db.Entry(p).State = EntityState.Modified;
//db.SaveChanges();
return true;
}
catch (Exception)
{
return false;
//throw;
}
}
}
}
So, the idea is very default: The first method is called by Get and returns the View of Edit. Then I need to save the changes by sending the post object from the view to the HttpPost Edit method.
My Model is something like that (I simplified it for better understanding):
MrSaleBeta01.Models
{
public class Post
{
public int Id { get; set; }
[ForeignKey("Category")]
public virtual int CategoryId { get; set; }
public virtual Category Category { get; set; }
}
public class Category
{
public Category()
{
this.Categories = new List<Category>();
this.Posts = new List<Post>();
}
#region Primitive Properties
public int CategoryId { get; set; }
public string Name { get; set; }
#endregion
#region Navigation Properties
public virtual IList<Post> Posts { get; set; }
#endregion
}
}
The idea: Every Post needs to have it's Category. Every Category can have multiple Posts or none. (1-N relationship).
The problem:
In the Edit (HttpPost) method, after I update the Category's objects (move the Post from it's category to a different category object. After that I do some other modifications on post object), I get an error in the line of the edit method:
db.Entry(post).State = EntityState.Modified;
saying that:
{"Attaching an entity of type 'MrSaleBeta01.Models.Post' 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."}
The error is beacuse there is a conflict to the line:
cold.Posts.Remove(post);
And even to the line:
cnew.Posts.Add(post);
I tried to use the solution of AsNoTracking() but without success, I also tried to change the line "db.Entry(post).State = EntityState.Modified" line to:
db.As.Attach(post)
but that line is even cannot be compiled.
What am I doing wrong? How can I solve that issue?