Problem with Adding multiple child objects to an existing entity in EF - asp.net

I need to add multiple child objects to an existing parent Object. I am instantiating my parent object and sets it Key/Id in my UI processing layer(to which my child objects will be added).
Parent parenttoModify = new Parent();
parenttoModify.Parent_Id = 5; //this comes from some Index of a dropdown or a key column of a grid, i Have put a dummy value here for example
parenttoModify.Children.Add(child);
parenttoModify.Children.Add(child2);
DataAccess.ModifyParent(parenttoModify);
In my data access layer I have a method like :
public static bool ModifyParent(Parent parent)
{
int recordsAffected=0;
using (TestEntities testContext = new TestEntities())
{
testContext.Parents.Attach(parent);
var parentEntry = testContext.ObjectStateManager.GetObjectStateEntry(parent);
parentEntry.ChangeState(System.Data.EntityState.Modified);
recordsAffected = testContext.SaveChanges();
}
return recordsAffected > 0 ? true : false;
}
I get an error when testContext.Parent.Attach(parent) is called. It says:
Object with same key already exist.
I am not sure why is this happening since i am not adding a parent object, I am just attaching it and adding child objects within it.
Any idea where I am going wrong?

Where do you add childs? I guess you are not showing all code. When you call Attach or AddObject EF always attaches or adds all entities from object graph which are not known (tracked) to context at the moment. The exception says that some entity - probably parent - is already tracked by the context. So you have either:
Used shared context (you are creating a new instance in ModifyParent so it should not be a case)
Load parent from the context first in ModifyParent
Called Attach or AddObject on any child before attaching parent.
All these operations lead to the exception you are receiving.

Related

Parent - child relationships in Realm

I am trying to move my Core Data object graph to Realm.
Currently I have an Entity called DBNode, which has
#NSManaged var children: NSSet
#NSManaged var parentNode: DBNode
where I can store the parent node and all the children of the node.
When I have a Realm object called RLMNode: RLMObject with
dynamic var children = RLMArray(objectClassName: RLMNode.className())
dynamic var parent = RLMNode()
it crashes when first trying to add an object.
Can I do this hierarchical structure in Realm?
Edit:
It seems I can do this, and just have one node in the array:
dynamic var parent = RLMArray(objectClassName:RLMNode.className())
Would this be the recommended way? Is it as quick as the object graph in Core Data?
The reason for the crash is probably that initialisation becomes recursive, when you create a node it creates a node for its parent, which in turn needs a node etc. You can check the stack trace to see if that is the case.
Realm in Swift supports optional object properties, and they are set to nil by default, so you can do something like this:
class DBNode: RLMObject {
dynamic var name = ""
dynamic var parent: DBNode?
dynamic var children = RLMArray(objectClassName: DBNode.className())
}
Arrays can in fact not be nil, and they do have to be initialised, but they can be empty.
Beware that you might get an exception thrown if you add both an object and its parent (or children) to the Realm explicitly.s They will be added automatically since you cannot link to objects that are not persisted.

Multiplicity constraint violated. The role '...' of the relationship '...' has multiplicity 1 or 0..1

I'm getting the following error from my DbContext: "Multiplicity constraint violated. The role 'MyEntity' of the relationship 'MyModel.FK_ChildEntities_MyEntities' has multiplicity 1 or 0..1."
using ASP.NET, Entity Framework 4
Working with a detached entity
The error happens the second time I try to reattach an entity to the dbcontext. The scenario is an unsuccessful save followed by a reattempt.
I have a detached entity in session. The user changes properties in a form, add things, removes things and finally clicks save. I get an attached copy of the entity from a new instance of the dbcontext, apply changes from the detached entity to the attached entity, validate, find an error and abort. The user changes whatever and saves again.
On the second save, the whole save process repeats, only this time it all goes to hell. Pretty much everything is duplicated, causing one error or another or all of them. Values from views and lookup tables that are only supposed to be references are created new and reassigned id's. Most of those issues I've been able to resolve, but I'm left with the multiplicity error. Child elements are being created as exact copies of other child elements, down to the unique id, only in the Added state. Or, if I reference certain properties, instead of cloning an unmodified child, it drops the new one. Either way, none of the code is executing as it did the first time around.
I'm discarding the instance of the dbcontext and the attached entity each save attempt. I thought that would be enough to revert any changes but something must be sticking around. The only thing not discared or reset is the detached entity, which is in session, but I dont make any changes to it. At least not directly.
The code (very simplified) is something like this:
void Save()
{
using (var context = new MyContext())
{
// detached entity from session
MyEntity detachedEntity = (MyEntity)Session["DetachedEntity"];
// attached entity from context
MyEntity attachedEntity = context.MyEntities.Single(x=>x.id == detachedEntity.id);
// <remove children representing lookup table elements from detachedEntity to prevent duplicates>
// <remove children representing view elements from detachedEntity to prevent duplicates>
// <apply changes from detachedEntity to attachedEntity>
// <add new children>
// <remove deleted children>
// <update modified children>
// <set entity state to unchanged on view and lookup elements of attachedEntity to ensure no duplicates...>
// <validate>
if (errors.count>0)
// <report errors>
else
context.SaveChanges();
}
}
as an example, this generates a multiplicity error:
// represents first save:
using (var context = new MyContext())
{
// detached entity from session
MyEntity detachedEntity = (MyEntity)Session["DetachedEntity"];
// attached entity from context
MyEntity attachedEntity = context.MyEntities.Single(x=>x.id == detachedEntity.id);
int debug1 = context.ChangeTracker.Entries<ChildEntity>().Count(); // debug1 == 0;
attachedEntity.ChildEntities.Add(detachedEntity.ChildEntities.First());
int debug2 = context.ChangeTracker.Entries<ChildEntity>().Count(); // debug2 == 1;
}
// represents second save:
using (var context = new MyContext())
{
// detached entity from session
MyEntity detachedEntity = (MyEntity)Session["DetachedEntity"];
// attached entity from context
MyEntity attachedEntity = context.MyEntities.Single(x=>x.id == detachedEntity.id);
int debug1 = context.ChangeTracker.Entries<ChildEntity>().Count(); // debug1 == 0;
attachedEntity.ChildEntities.Add(detachedEntity.ChildEntities.First());
int debug2 = context.ChangeTracker.Entries<ChildEntity>().Count(); // multiplicity error;
}
somehow the dbcontext remembers what objects were added to it. if the exact same object shows up twice, it... blows
instead of adding child entities from my detached entity to the attached one, i should've been creating new copies of each child
ChildEntity detachedChild = detachedEntity.ChildEntities.First();
attachedEntity.ChildEntities.Add(new ChildEntity {
propertyA = detachedChild.propertyA,
propertyB = detachedChild.propertyB
});
instead of
attachedEntity.ChildEntities.Add(detachedEntity.ChildEntities.First());
The problem is that detachedChild.parent should be assigned attachedParent.
foreach(var detachedEntity in detachedEntities)
{
attachedEntity.ChildEntities.Add(detachedEntity);
detachedEntity.ParentEntity = attachedEntity;
}
What you are trying to do is something like:
ChildEntity childEntity = new ChildEntity()
{
//do mapping or provide data EXCEPt THE PRIMARY KEY
}
foreach(ParentEntity parentEntity in parentEntities)
{
parentEntity.Add(childEntity);
}
_dbContext.SaveChanges();
Result
Multiplicity constraint violated. The role '…' of the relationship '…' has multiplicity 1 or 0..1
The reason of the error message is
that everytime the _dbContext adds the childEntity to some parentEntity, it sets the generated primary key to the childEntity, so in the second loop of the foreach the primary key will be duplicated
The fix is - Method #1 - for simple scenarios
foreach(ParentEntity parentEntity in parentEntities)
{
//Make a new object every time
ChildEntity childEntity = new ChildEntity()
{
//do mapping or provide data EXCEPt THE PRIMARY KEY
}
parentEntity.Add(childEntity);
}
_dbContext.SaveChanges();
The fix is - Method #2 - for complex scenarios
using YOUR_PROJECT.ANY_FOLDER.DeepCopyExtensions;
ChildEntity childEntity = new ChildEntity()
{
//do mapping or provide data EXCEPt THE PRIMARY KEY
}
foreach(ParentEntity parentEntity in parentEntities)
{
//makes a copy of the childEntity object and pass it to the _dbContext, after saving each copy will be separated and the original object childEntity wont be touched
parentEntity.Add(DeepCopyByExpressionTrees.DeepCopyByExpressionTree(childEntity));
}
_dbContext.SaveChanges();
What is this method "DeepCopyByExpressionTrees.DeepCopyByExpressionTree(childEntity)" ?
Check this project here, download the source code, and only include the class file "DeepCopyByExpressionTrees.cs" to your project as a helper class and start using it any where.
Thanks
Make sure to inspect the properties of the object you are trying to add. In my case it was mistakenly referencing the same invalid object on each add which it didn't like and thus threw the same error you have here.
EF 6 Update
For me setting object state to added worked on sounds logical also
ChildEntity detachedChild = detachedEntity.ChildEntities.First();
var newChild = new ChildEntity {
propertyA = detachedChild.propertyA,
propertyB = detachedChild.propertyB
});
// Mark all added entity entity state to Added
attachedEntity.ChildEntities.Add(newChild );
db.Entry(newChild ).State = EntityState.Added;
http://www.entityframeworktutorial.net/EntityFramework4.3/update-one-to-many-entity-using-dbcontext.aspx
I experienced this error when I had navigation properties that had not been set or navigation properties that belonged to the wrong Code First DBContext
I fixed this by making the child collections in the parent entity virtual. This allows one to easily Update the entity when its child collections don't change, which, for me, was most of the time.
I had a similar issue, but mine arose from a AsNoTracking() after my query.
I had something like this
var myObject = dbContext.GetRepo<myType>().Query().AsNoTracking().SingleOrDefault()
And then later on I use that object to set anther object.
var myChild = new Child { parent = myObect }
and apparently EntityFramework tries to create a brand new object and hence causes a multiplicity error.

swt/jface databinding: PojoProperties vs PojoObservable

I'm writing a JFace dialog, and I'd like to use databing to a model object.
Looking at code I can see that there are times when I find a PojoProperties used to build the binding, while other time it is used a PojoObservables.
Looking at the Javadoc I can read:
PojoObservables: A factory for creating observable objects for POJOs (plain old java objects) that conform to idea of an object with getters and setters but does not provide property change events on change.
PojoProperties: A factory for creating properties for POJOs (plain old Java objects) that conform to idea of an object with getters and setters but does not provide property change events on change.
The same question applies to the difference that exists between BeansObservables and BeansProperties
The (obvious) difference sems to be that the observable allows to observe objects and the properties allows to observe properties, but since a Pojo has a getter and a setter for its data, what is the difference between them? And which of them should I choose for my dialog?
Here follows a code excerpt:
The POJO:
public class DataObject {
private String m_value;
public String getValue() {
return m_value;
}
public void setValue(String i_value) {
m_value = i_value;
}
}
The DIALOG (relevant part):
#Override
protected Control createDialogArea(Composite parent) {
Composite container = (Composite) super.createDialogArea(parent);
m_combo = new Combo(container, SWT.BORDER);
m_comboViewer = new ComboViewer(container, SWT.NONE);
}
The BINDING (relevant part):
// using PojoObservable
IObservableValue observeValue = PojoObservables.observeValue(m_dataObject, "value");
IObservableValue observeWidget = SWTObservables.observeSelection(m_combo);
// using PojoProperties
IObservableValue observeValue = PojoProperties.value("value").observe(m_dataObject);
IObservableValue observeWidget = ViewerProperties.singleSelection().observe(m_comboViewer);
I understand that one time I'm using a combo and another I'm using a ComboViewer, but I can get the combo from the viewer and bind the other way if I need...
Also, can I mix the two, for example use the observeValue with the ViewerProperties?
IObservableValue observeValue = PojoObservables.observeValue(m_dataObject, "value");
IObservableValue observeWidget = ViewerProperties.singleSelection().observe(m_comboViewer);
I am playing around a little with JFace viewers (especially ComboViewer) & databinding and discovered that if I use
SWTObservables.observeSelection(comboViewer.getCombo());
then databinding is not working correctly.
However, if I use
ViewersObservables.observeSingleSelection(comboViewer);
Then everything is working as expected.
Maybe this is a special for my case, so to get it a better overview I'll describe my set up in following paragraph.
I have modelObject with field named selectedEntity and entities and bind this ComboViewer to the modelObject.
I want to display all "entities" in model object, if I add any entity to the modelObject.entities collection then I want to this entity be added to combo automatically.
If user selects some item in combo I want to modelObject.selectedEntity be set automatically.
If I set modelObject.selectedEntity I want to combo selection be set automatically.
Source code can be found at: https://gist.github.com/3938502
Since Eclipse Mars, PojoObservables is deprecated in favor of PojoProperties and BeansObservables is deprecated in favor of BeanProperties so the answer to which one should be used has now become evident.

Flex: Passing object to save back to server freezes application

I have a NavigatorContent which is displayed when the user selects an item in a DataGrid.
This NavigatorContent contains a form and an accordion displaying the related objects.
When the user presses the Save button in the NavigatorContent the form and the children should be saved to the database by calling the server through BlazeDS:
saveObjectToDB()
{
//Map the form values to the object
object.field1 = object_field1.text;
object.field2 = object_field2.selectedDate as Date;
object.relatedobject3 = comboBox.selectedItem as RelatedObject3;
//etc.....
//Loop through accordion to save the child objects
for(var i:int= 0; i < accordion.numChildren; i++ )
{
if(accordion.getChild(i) is RelatedObject1Form)
{
var formRelated1:RelatedObject1Form = accordion.getChild(i) as RelatedObject1Form;
//Map the form values to the related object
object.relatedobject1.field1 = formRelated1.relatedobject1_field1.selectedDate;
//etc...
}
if(accordion.getChild(i) is RelatedObject2Grid)
{
var gridRelated2:RelatedObject2Grid = accordion.getChild(i) as RelatedObject2Grid;
//Get dataProvider for the datagrid of the relatedObject
object.relatedobject2 = gridRelated2.object.relatedobject2;
}
}
// Call the remoting object's saveObject method
var saveObjectOperation:Operation = new Operation();
saveObjectOperation.name = "saveObject";
saveObjectOperation.arguments=[object];
ro.operations = [saveObjectOperation];
saveObjectOperation.send();
if(isNewObject)
//dispatchEvent new object
else
//dispatchEvent object updated
}
My problem is as the question states that my application freezes for a few seconds when the user presses the save button that calls this method. I guess that is because Flex is single threaded, but still i dont quite get why this method would be so computational expensive? It doesnt seem to matter if i comment out the loop that loops over the accordion children.
I tried setting the objects related objects to null before calling the remote save method, and this seemed to speed up the save method, but it provided me with some troubles later.
My conclusion is that the remote call is whats freezing up the application, and if i set the related objects to null this seems to fix the issue. But is this really necessary? The related objects aren't really that big, so i don't quite get why the remote call should freeze the application for a few seconds.
This is how i create the accordion children when the NavaigatorContent is intialized:
var relatedObjectForm:RelatedObject1Form= new RelatedObject1Form();
accordion.addChild(relatedObjectForm);
relatedObjectForm.object= object;
relatedObjectForm.ro = this.ro;
The object that i pass to the accordion children is public and [Bindable] in the NavigatorContent and in the accordion children and is initially passed from the main DataGrid. May this be a problem relating to this issue?
Any help/comments is much appreciated. This issue is starting to affect my beauty sleep ;)
My guess would be that you're spending a lot of time in the serializer. Put a trace target in the app and watch the console when it runs to see what's being sent.
The most likely problems are from DisplayObjects - if they've been added to the application they will have a reference to the application itself, and will cause some serializers to start serializing the entire app. The bindable object might have some odd events attached that eventually attach to DisplayObjects - try copying the relevant values in it into your object instead of just taking a reference to the existing object.

Null cast between parent and child objects

I have a flex application with two objects: a parent widget (called an IBaseWidget) and a child widget (called a HelperWidget2). When the user clicks on a help link, a helper widget is loaded into the list of base widgets and then displayed for the user.
However, when I try to access this child widget by casting the base widget in the collection to the child widget type, the child widget returns null and I am unable to work with the widget.
The following snippet correctly returns the widget ID of the newly added widget and dispatches an event to load the widget:
var id:Number = WidgetManager.getInstance().getWidgetId("Helper");
ViewerContainer.dispatchEvent(new AppEvent(AppEvent.WIDGET_RUN, id, openQuickQueryCanvas));
Once the widget is loaded, a callback function called openQuickQueryCanvas() attempts to do another action with the helper widget:
private function openQuickQueryCanvas():void{
var id:Number = WidgetManager.getInstance().getWidgetId("Helper");
var bWidget:IBaseWidget = WidgetManager.getInstance().getWidget(id) as IBaseWidget;
var helperWidget:HelperWidget2 = bWidget as HelperWidget2;
if(helperWidget != null){
helperWidget.quickQueryCanvas.dispatchEvent(new MouseEvent(MouseEvent.CLICK));//fire an event to open the quick query canvas
}
}
The problem is that helperWidget above always returns null, meaning the cast isn't successful. This doesn't make sense to me, because bWidget is of type HelperWidget2.
Any thoughts? I'm stumped...
First off, make sure that HelperWidget2 implements IBaseWidget like so
public class HelperWidget2 implements IBaseWidget
Second, I would suggest using the is keyword instead of casting and checking for null:
private function openQuickQueryCanvas():void {
var id:Number = WidgetManager.getInstance().getWidgetId("Helper");
var bWidget:IBaseWidget = WidgetManager.getInstance().getWidget(id) as IBaseWidget;
if(bWidget is HelperWidget2)
{
HelperWidget2(bWidget).doWhatever();
}
}
Cast the returning instance as an object, instead of HelperWidget2. You won't have intellisense for the methods at design time, but more importantly, it won't be null at run time.
var bWidget:Object = WidgetManager.getInstance().getWidget(id);
bWidget.doWhatever();

Resources