EF 6 Saving multiple levels of child entities and multiple parents - c#

Given this model:
I would like to be able to save in one SaveChange call the relations. Which means, I either have a new or updated ContainerParent, and multiple first level children and each of those can have 1 or 2 levels deeper.
The thing is, the children both have a key to themselves, for finding its parent, and a key to the container, for the container to get all its Children independently of their hierarchical level.
With this pseudo code (in the case of all entities are created, not updated)
var newContainerParent = context.ContainerParents.Add(new ContainerParent());
var rootChild = context.Children.Add(new Child());
var secondLevelChild = new Child();
var thirdLevelChild = new Child();
secondLevelChild.Children.Add(thirdLevelChild);
rootChild.Children.Add(secondLevelChild);
newContainerParent.Children.Add(rootChild);
context.SaveChanges();
Problem with this code, is that only the rootchild will have the FK for the container set. I also tried to add the children to they child parent AND the container:
rootChild.Children.Add(secondLevelChild);
newContainerParent.Children.Add(rootChild);
newContainerParent.Children.Add(secondLevelChild);
newContainerParent.Children.Add(thirdLevelChild);
I have the same problem while updating an existing container with new children. I set all the children with the already existing key of the parent, but when SaveChanges is called the key is not saved, its reverted to null.
I fixed it by doing all this in 2 steps, saving once and then getting all the newly created children and updating them with the parent key, the calling SaveChanges again.
I have a feeling I'm missing something, that I should not need to save twice.

The number or frequence of SaveChange calls have no implication on anything, not on performance or so. So why do you want to minimize it ?
Actually, storing such a self referencing table with one SaveChanges is not possible,
cause the ID of an new entity, is generated, when it is saved. So you first need to save it, and then you get the ID, that you can store in another entity. This might require further update-Commands, to the entity you just stored.
You have two chances to solve this.
1) manually generated ID's, handle it all yourself and you know the ID before your store it.
2) In case you have no circularity in your dependency, so a perfect tree structure, you save the items top-down, level by level. I assume you have the childs having a reference to it's parents, so the root has no reference to any other items, you save that first, than the 1st level children, and so on.
This requires multiple SaveChanges, but this is not a disadvantage. It is one Insert-SQL-Command per entity anyway, no matter if you do it in 1 SaveChanges or in 100 SaveChanges.
Both solutions avoid "Update" Commands to the entities, they do Inserts only.
Entity Framework could actually find out this dependencies itself and create an order for new entities to insert, but this is not implemented today, or not perfect, especially on self-referenced tables. The order of saving items is kind of random. So you have to enforce the order with intermediate SaveChanges.

Related

NHibernate, Add parent if not exists when adding child

I'm using this code to determine if it should create a parent or if the parent already exists:
var id = 1;
var parent = Session.Get<Parent>(id);
if (parent == null)
parent = new Parent();
var child = new Child();
child.Parent = parent;
parent.Children.Add(child);
Session.Save(parent);
Right now this seems very inefficient, this method queries the database with 3 separate sql queries everytime when a child is added:
Get parent based on id
Insert child
Insert/update parent (depending if the parent did exist)
Could i do this in a better way?
There are two scenarios in fact.
In the first case, when we really do not know, if there is a parent with provided id - there's no other way. Such solution will always require so many sql statements.. to find out if there is a parent and insert if not.
In the second scenario, if we do know that there is a parent in DB (with provided id) - we can make it more efficient with a built in support: Load<Parent>(id)
9.2. Loading an object
... Load() returns an object that is an uninitialized proxy and
does not actually hit the database until you invoke a method of the
object...
Get more details here:
NHibernate difference between Query<T>, Get<T> and Load<T>
Given that you are in a regular business logic development, I wouldn't mind these queries.
Get is quite fast, because it usually performs a lookup by primary key, which usually is a clustered index (don't know about SQLite).
Existing parents need to be found to be linked anyway. You can postpone the actual query by using Load, but in my experience you need the parent anyway.
Updating the parent may be unnecessary. What does it update? Is there a missing inverse-mapping?
If you are doing the whole thing for a lot of records (not only one), you may consider other options. (Batches, pre-fetching, Futures, whatever.)
If you think that you need a highly optimized implementation for exactly this code, you should consider to avoid using an ORM and implement it in plain SQL (and recheck if it would really use less queries). Writing object oriented code requires having objects in memory which sometimes requires getting data from the database that wouldn't be required in a highly optimized implementation.

Workflow for data from Backbone through NHibernate

This question isn't code-centric, it's a question about idioms. I'm using Backbone/Marionette on the front and C#, NHibernate in the back.
I've got a few tables mapped and working for creates and updates. For simplicity, say I've got two tables, a parent and child, and the child has potentially many rows. The child reference to the parent is not-nullable, so I've got an Inverse relationship, and that's all working. The flow of data from Backbone to the Controller to NHibernate is pretty simple, and I'm using ISession.SaveOrUpdate() at the end. I can post mappings and so forth if necessary. I will say that the mappings Fluent NHibernate generates uses a Bag on the parent.
Here's a concrete example of the situation I'm trying to understand. Say I've got a parent entry with two rows in the child table. I manipulate the data so that one of the children is removed, but no other changes are made. Javascript sends over an object "tree" with the parent entry and the one child row that's left. The mappings are all handled fine, but the sql that's generated is a bunch of (unnecessary, but whatever) update statements. What I would like to happen instead is that NHibernate notices that there is only one child relationship in this new object, but there are two children in the actual database, and then NHibernate deletes that other child. The 'cascade-delete-orphans' option is not working, because the other child isn't actually being orphaned. It still has a reference to the parent in the fk column, and that column is non-nullable anyway, which is why I used the Inverse mapping option.
Is that possible to setup in the mappings? If not, what is a good way to tackle this situation?
Since you are sending an object from the client side, and then create the entity from that object and try to persist, NHibernate will not automatically delete the child entity since it does not know the child object is deleted (it only see you are only try to update one parent entity and a child entity), which is correct in my opinion. For example if you want to just update the parent entity field, then you have to load entire object graph to do it, otherwise NHibernate will delete all children since they are not loaded.
What you should do here is to load the parent entity, and remove missing child entity(s) deleted from it and then persist (instead of mapping the entity), code should look like following,
void Update(ParentDto parentDto){
Parent parent = _session.Get<Parent>(parentDto.Id);
//update parent fields
var childRemoved = //find removed child from parent;
parent.Children.Remove(childRemoved);
_session.SaveOrUpdate(parent);
}

How does DetectChanges work?

There is the following 2 entities, with the following properties:
Parent
ID
Children
Child
ID
ParentID
Parent
Now I have the following code:
db.Configuration.AutoDetectChangesEnabled = false;
var child1=new Child();
parent.Children.Add(child1);
db.ChangeTracker.DetectChanges();
parent.Children.Remove(child1);
var child2=new Child();
child2.Parent=parent;
child2.ParentID=parent.ID;
db.Children.add(child2);
At this point, child1 and child2 are completely identical. The Parent and ParentID properties have the same values (that of parent). Examining the dbContext entry for both of them also shows exactly the same information, e.g. OriginalValues is empty for both.
If I now call db.ChangeTracker.DetectChanges however, child1.Parent becomes null, while child2.Parent keeps its value. How does EF know to do this - where does it keep the info needed to be able to make this difference?
Thank you for any ideas
In general
Detect Changes works by detecting the differences between the current property values of the entity and the original property values that are stored in a snapshot when the entity was queried or attached.
Entity Framework Automatic Detect Changes
and
Ensures that ObjectStateEntry changes are synchronized with changes in all objects that are tracked by the ObjectStateManager.
ObjectContext.DetectChanges Method
so in your example after you disable change tracking the new values are on top of the original values until you decide to update the model by calling context.ChangeTracker.DetectChanges and synchronize all objects (it more or less defers the operations). Now when you call DetectChanges all operations (Remove & Add) get commited to the model so that they can be saved later. Thus the parent is removed from the child1 parent.Children.Remove(child1) and child2 keeps its value because here the operation was to add the parent (assignment).
The reason why you would want to disable change tracking is performace:
If you are tracking a lot of entities in your context and you call one of these methods many times in a loop, then you may get significant performance improvements by turning off detection of changes for the duration of the loop.
If you'd like to know the exact technical/implementation details you can digg through the source code:
.NET Framework source code online > DetectChanges

What's the proper way to update parent/child entities in EF?

I'm using Ef 4 code first and have a parent table with a child
When I update the parent, I notice that the child is not updated, rather new entries are created (old ones are not deleted).
My update method looks like so:
IEFRepository<Parent> repo = new EFRepository<Parent>( context );
var parent = repo.GetSingle(m => m.parentId.Equals(updatedParent.parentId));
parent.Child = updatedParent.Child; //this is creating a new record in the db, not overwriting the existing
repo.Update(parent);
If I break out the child properties in the update method like below it solves the duplicate entry problem, but creates other issues elsewhere (primarily with validating null entries).
parent.Child.property = updatedParent.Child.property;
I also tried creating an UpdateChild(), and calling that from UpdateParent(), but got essentially the same result as breaking out the individual child properties
Is there a proper way to control this behavior and force EF to overwrite the child entity instead of creating a new one?
Have a list of childs in a context and remove old child from your context when you don't need it anymore.

What is the difference between IDbSet.Add and DbEntityEntry.State = EntityState.Added?

In EF 4.1+, is there a difference between these 2 lines of code?
dbContext.SomeEntitySet.Add(entityInstance);
dbContext.Entry(entityInstance).State = EntityState.Added;
Or do they do the same thing? I'm wondering if one might affect child collections / navigation properties differently than the other.
When you use dbContext.SomeEntitySet.Add(entityInstance); the status for this and all its related entities/collections is set to added, while dbContext.Entry(entityInstance).State = EntityState.Added; adds also all the related entities/collections to the context but leaves them as unmodified.
So if the entity that you are trying to create has a related entity (and it's value its not null), when you use Add it will create a new object for that child entity, while with the other way it won't.
I just tested this with EF 6, with related entities/navigation properties, and in both cases the created objects were identical. (All parent and related child objects were created.) The only difference I noticed was that Add was faster by about a factor of 2. My data had 1000 parent objects, each with 5 child objects for a total of 6000 objects written to the DB.

Categories

Resources