I’m using Entity Framework 4 and WPF with the MVVM pattern. Now I’m facing the horrible
The relationship between the two objects cannot be defined because
they are attached to different ObjectContext objects
message. I know the reason for it but I can’t seem to figure out how to get around it.
Here is what I’m trying to achieve (simplified). On the left hand side of my application, I have a list of associations. I then select a single one, create a new Context for that association (I don’t want a single context for the lifetime of the application as there can by multiple windows open and that could lead to problems. So it’s one window one context) and update a lot of fields (mostly of type DateTime) which works fine. Databinding, updating the database etc….
However, I also have a combobox where I need to select the president of the association from a collection of Contact objects. For performance reasons, I load all the contacts once at the application startup through an ObjectContext.
My Comite EntityObject has a navigation property called President of type Contact. The Combobox’s SelectedItem is bound to Comite.President like so:
<ComboBox Grid.Row="0" Grid.Column="1" ItemsSource="{Binding Contacts}" DisplayMemberPath="FullName" SelectedItem="{Binding Path=Comite.President}" VerticalAlignment="Center"/>
Whenever I select an item from the combobox, the above exception is thrown and I can’t figure out why. I disabled all of my Context.SaveChanges() calls. I tried handling the PropertyChanging and PropertyChanged event. I tried handling the Association.PresidentReference.AssociationChanged event but none get called. The exception happens on IDE generated code here:
[XmlIgnoreAttribute()]
[SoapIgnoreAttribute()]
[DataMemberAttribute()]
[EdmRelationshipNavigationPropertyAttribute("GestionSyndicatsDeChasse", "FK_Comite_ContactsPresident", "Contacts")]
public Contacts President
{
get
{
return ((IEntityWithRelationships)this).RelationshipManager.GetRelatedReference<Contacts>("GestionSyndicatsDeChasse.FK_Comite_ContactsPresident", "Contacts").Value;
}
set
{
//Exception is thrown here!
((IEntityWithRelationships)this).RelationshipManager.GetRelatedReference<Contacts>("GestionSyndicatsDeChasse.FK_Comite_ContactsPresident", "Contacts").Value = value;
}
}
I don’t want to temper with that code as it is being generated by VS.
The problem can be worked around if I recreate the Contacts Collection from the same context as the association is coming from, but that is an enormous performance hit and I wan’t to avoid it as every time I select another association, I also need would need to recreate the contacts collection (query from the context)
So my question is: how can I select from the combobox the Contact to be associated with the President NavigationProperty? I’d somehow need to attach the contact to the correct context, but there is no place I can do that. The code doesn’t reach any of my breakpoints.
Here is the Stacktrace from the exception:
at System.Data.Objects.DataClasses.RelatedEnd.Add(IEntityWrapper
wrappedTarget, Boolean applyConstraints, Boolean
addRelationshipAsUnchanged, Boolean relationshipAlreadyExists, Boolean
allowModifyingOtherEndOfRelationship, Boolean forceForeignKeyChanges)
at System.Data.Objects.DataClasses.RelatedEnd.Add(IEntityWrapper
wrappedEntity, Boolean applyConstraints) at
System.Data.Objects.DataClasses.EntityReference1.set_ReferenceValue(IEntityWrapper1.set_Value(TEntity
value) at
System.Data.Objects.DataClasses.EntityReference
value) at
GestionSyndicatsDeChasse.Model.Comite.set_President(Contacts value) in
C:\Documents and Settings\Administrator\my documents\visual studio
2010\Projects\CDD\GestionSyndicatsDeChasse\GestionSyndicatsDeChasse\Model\ChasseModel.Designer.cs:line
685
Also, In the debugger, I wanted to check the call Stack. Unfortunately, except the line of code where the error happens, everything else is ‘External Code’
I hope someone can help me here.
You are likely going to have to break up the SelectedItem binding. I have done this before in MVVM without much problem. Create a property on your VM that mirrors the value of a property on your underlying model class. Lets use your president example. Both the Comite and the VM (I will refer to this as ComiteViewModel hereafter) will have a President property. The ComiteViewModel should be able to retrieve a reference to the context to which both the Contact and Comite entities belong.
In the property Setter on the ViewModel, before pushing the value to the entity, detatch it from it’s context, attach it to the Comite context, set it as modified, make your changes (really I think these two steps can go in any order), and save changes, then you might refresh the Comite entity just for a warm and fuzzy. You may need to detach and reattach to the Contacts context afterward.
The below is just a mockup. I don’t have proper access to examples at the moment, but it should give you some ideas.