Answered by:
STE POCO Many To Many Save Issue - Many to Many is always inserting

Question
-
I have two entities in my model, Question and PotentialAnswer. They have an association in which the PotentialAnswers has a collection of Questions and the Question has a collection of PotentialAnswer. The Association Set Name is QuestionPotentialAnswerXref, which holds the "many-to-many" concept, which is also the cause of my problems currently.
The problem is in the object model, due to disconnected as these are the self-tracking entities, have to explicity call the AcceptChanges method on each object as the state will change to Added. Currently, the entire object graph is all set to Unchanged when doing a save as I am calling the AcceptChanges within everything I have access to in the object graph. Unfortunately, the only declaration I see in code is in the edmx file for QuestionPotentialAnswerXref. So when I save, it is always trying to implicity insert a QuestionPotentialAnswerXref.
Does anyone have a solution to this problem?
Friday, January 14, 2011 3:48 PM
Answers
-
You have to monitor the ObjectsAddedToCollectionProperty and ObjectsRemovedFromCollectionProperty of the ChangeTracker on both your Question entity and PotentialAnswer entity. This is where many-to-many relationships are tracked.
For example, if you have an existing myQuestion, and you say
myQuestion.PotentialAnswers.Add( myPotentialAnswer )
This will put a record for myPotentialAnswer in the myQuestion.ChangeTracker.ObjectsAddedToCollectionProperty. Likewise, you'll also find the myQuestion in the myPotentialAnswer.ChangeTracker.ObjectsAddedToCollectionProperty.
You are likely running into issues when you are performing this action with a myQuestion and myPotentialAnswer where they are already associated. If you an envision something like:
var myQuestion = myService.GetQuestion( 1 ); var myAnswers = myService.GetAnswersForQuestion( 1 ); myAnswers.ForEach( myQuestion.PotentialAnswers.Add );
This will make the ChangeTracker for both the myQuestion and all myAnswers think the associations are brand new. If you then do something along the lines of:
var myResult = myService.SaveQuestion( myQuestion );
You will run into some Constraint violations from your database. To make this work you have to change:
myAnswers.ForEach( myQuestion.PotentialAnswers.Add );
To something more like:
myQuestion.StopTracking(); myAnswers.ForEach( answer => { answer.StopTracking(); myQuestions.PotentialAnswers.Add( answer ); answer.StartTracking(); } myQuestion.StartTracking();
By shutting off ChangeTracking, calling Add() on the PotentialAnswers collection will no longer place references in the ObjectsAddedToCollectionProperty.
If this is your scenario, I have a new code-generation template called "Enhanced Self-Tracking Entities" that simplifies this code:
myQuestion.AttachPotentialAnswers( myAnswers )
It is a Visual Studio 2010 extension that once installed provides the code-generation item to those available when selecting "Add Code Generation Item" from the EDMX designer. It includes additional methods for safely manipulating object graphs for existing related entities without fear of the ChangeTracker making incorrect assumptions. I have described them in this post:
Please contact me via email if you are interested in obtaining this extension: refereejoe at gmail dot com
Saturday, January 22, 2011 12:09 AM
All replies
-
Hi Joseph,
Thanks for your post.
According to your description, I'm not clear about your question.
>>>>>Currently, the entire object graph is all set to Unchanged when doing a save as I am calling the AcceptChanges within everything I have access to in the object graph.
Would you please feel free to clarify your question and give us some code, My e-mail address is: v-alacheatmicrosoftdontcom
Have a nice day.
Alan Chen[MSFT]
MSDN Community Support | Feedback to us
Get or Request Code Sample from Microsoft
Please remember to mark the replies as answers if they help and unmark them if they provide no help.
Monday, January 17, 2011 7:10 AM -
Hi Joseph,
I am writing to check the status of the issue on your side. Would you mind letting us know the result of the suggestions?
If you need further assistance, please feel free to let me know. I will be more than happy to be of assistance.Have a nice day.
Alan Chen[MSFT]
MSDN Community Support | Feedback to us
Get or Request Code Sample from Microsoft
Please remember to mark the replies as answers if they help and unmark them if they provide no help.
Friday, January 21, 2011 1:20 AM -
You have to monitor the ObjectsAddedToCollectionProperty and ObjectsRemovedFromCollectionProperty of the ChangeTracker on both your Question entity and PotentialAnswer entity. This is where many-to-many relationships are tracked.
For example, if you have an existing myQuestion, and you say
myQuestion.PotentialAnswers.Add( myPotentialAnswer )
This will put a record for myPotentialAnswer in the myQuestion.ChangeTracker.ObjectsAddedToCollectionProperty. Likewise, you'll also find the myQuestion in the myPotentialAnswer.ChangeTracker.ObjectsAddedToCollectionProperty.
You are likely running into issues when you are performing this action with a myQuestion and myPotentialAnswer where they are already associated. If you an envision something like:
var myQuestion = myService.GetQuestion( 1 ); var myAnswers = myService.GetAnswersForQuestion( 1 ); myAnswers.ForEach( myQuestion.PotentialAnswers.Add );
This will make the ChangeTracker for both the myQuestion and all myAnswers think the associations are brand new. If you then do something along the lines of:
var myResult = myService.SaveQuestion( myQuestion );
You will run into some Constraint violations from your database. To make this work you have to change:
myAnswers.ForEach( myQuestion.PotentialAnswers.Add );
To something more like:
myQuestion.StopTracking(); myAnswers.ForEach( answer => { answer.StopTracking(); myQuestions.PotentialAnswers.Add( answer ); answer.StartTracking(); } myQuestion.StartTracking();
By shutting off ChangeTracking, calling Add() on the PotentialAnswers collection will no longer place references in the ObjectsAddedToCollectionProperty.
If this is your scenario, I have a new code-generation template called "Enhanced Self-Tracking Entities" that simplifies this code:
myQuestion.AttachPotentialAnswers( myAnswers )
It is a Visual Studio 2010 extension that once installed provides the code-generation item to those available when selecting "Add Code Generation Item" from the EDMX designer. It includes additional methods for safely manipulating object graphs for existing related entities without fear of the ChangeTracker making incorrect assumptions. I have described them in this post:
Please contact me via email if you are interested in obtaining this extension: refereejoe at gmail dot com
Saturday, January 22, 2011 12:09 AM