KnoxCorsair KnoxCorsair - 1 month ago 14
Ajax Question

An entity object cannot be referenced by multiple instances of IEntityChangeTracker error while trying to insert

I've started experimenting with the Web API a bit, and struggling to get it to work. I have an ordinary MVC 5 project set up, in this I have models for the different types of data I'm handling, and also ordinary, that is, non Web API controllers.

Now what I've done is install Web API into the project. The thought here is to by using Ajax, send data when a user clicks a button, through a POST to the Web API controller I've set up.

What i want to do here then is to recieve the data, and using EF6, save it to a SQL Database.

However. I keep getting the error in the title of this question. I've searched around and yes there are answers around but simply put I just don't understand them and how to apply it to my code to make it work.

So, some code. This is from my view, where i have a form and a send button. When a user clicks this a Ajax request is initiated.

var chatMessage = new Object();
chatMessage.ChatMessageOwner = "87b1e521-9c62-4d31-9cc7-a92b2b6b7db1";
chatMessage.ChatMessageText = "Test";
chatMessage.ChatMessageTime = 2016 - 11 - 01;
chatMessage.Grouppe = 4;


$.ajax({
url: '/api/ChatMessages/post',
type: 'POST',
dataType: 'json',
data: chatMessage,
success: function (result) {
alert(result);
},
error: function (err) {
alert(err.statusText);
console.log(err.statusText);
}
});


So first of, the model I'm using for these messages looks like this

public class ChatMessage
{
public int ChatMessageID { get; set; }

[Required(ErrorMessage = "A value has to be entered.")]
[StringLength(1000)]
[DisplayName("Message")]
public string ChatMessageText { get; set; }

[Required(ErrorMessage = "A value has to be entered.")]
[DataType(DataType.Date)]
[DisplayName("Chat message timestamp")]
public DateTime ChatMessageTime { get; set; }

[Required(ErrorMessage = "A value has to be entered.")]
public virtual ApplicationUser ChatMessageOwner { get; set; }

[Required(ErrorMessage = "A value has to be entered.")]
public virtual Grouppe Grouppe { get; set; }
}


So i create a object and then i send this through a Ajax POST to the Web Api Controller i want to use. The Method responding to this request looks like this

[Route("api/ChatMessages/post")]
[ResponseType(typeof(ChatMessage))]
public async Task<IHttpActionResult> PostChatMessage(ChatMessage chatMessage2)
{
ApplicationUser user = System.Web.HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>().FindById(System.Web.HttpContext.Current.User.Identity.GetUserId());
ChatMessage chatMessage = new ChatMessage();
Grouppe grouppe = new Grouppe ();
grouppe.GrouppeID = 4;

chatMessage.ChatMessageOwner = user;
chatMessage.ChatMessageText = "Test";
chatMessage.ChatMessageTime = DateTime.Now;
chatMessage.Grouppe.GrouppeID = grouppe.GrouppeID;

db.ChatMessage.Add(chatMessage);
await db.SaveChangesAsync();

return CreatedAtRoute("DefaultApi", new { id = chatMessage.ChatMessageID }, chatMessage);
}


When debugging the
chatMessage
object seems to get populated as intended, containing the objects for
grouppe
and "user". I can also fetch the text and date as intended (I have replaced that with some debugging-dummie-code now). However when reaching the line
db.ChatMessage.Add(chatMessage)
where I'm trying to actually add this to the database, I get the error in the title.

I just have no idea what to do, and I cant see how I'm using multiple contextes and such.

All help is very much appreciated, thanks a lot in advance!

Answer

It seems like your DbContext are not reinstantiated when you hit the PostChatMessage action.

You can fix the issue by doing this:

// Delete the db private field and use local variable.
using (var db = new ApplicationDataContext()) 
{
    var user = db.Users.Find(System.Web.HttpContext.Current.User.Identity.GetUserId());
    ChatMessage chatMessage = new ChatMessage();
    Grouppe grouppe = new Grouppe ();
    grouppe.GrouppeID = 4;

    chatMessage.ChatMessageOwner = user;
    chatMessage.ChatMessageText = "Test";
    chatMessage.ChatMessageTime = DateTime.Now;
    chatMessage.Grouppe = grouppe; // Side note: here set the navigational property directly.

    db.ChatMessage.Add(chatMessage);
    await db.SaveChangesAsync();
}