I have a object structure like this:
public class Entity
{
IList<Relationship> Relationships{get;set;}
}
public class Relationship
{
public Relationship(Entity parent, IList<Entity> children)
{
//set properties
}
Entity Parent{get;private set;}
IList<Entity> Children{get;private set;}
}
The Relationship contains all information about the parent and child instances, and I would like to share the same Relationship instance on the parent and all child instances that make up the relationship.
Now when I come to load my entities from the db I start with the top entity, which then loads the relationships. I thought I could just cache the relationship I am building and reuse the same instance for the children. But this doesn't work as to create a relationship I need to load all child entities, so each child entity tries to recreate the same relationship I am currently trying to get the children for before it has been created, so I end up creating all of the relationship instances below me in the tree before I can add the relationship to the cache.
Is there a way I can get round this without making the children a settable property of my relationship, so I can create the reference to the relationship before the children are created?
So I managed this by introducing a RelationshipBuilder class which I used to keep track of the parents and children of a relationship without actually creating it.
This enabled me to load an entity and create its relationships in the builder, when the relationships tried to create the children they checked with the builder to see that the relationship was already being created and returned.
This meant I could navigate all the way down the hierarchy loading all of the entity instance and setting the parent entity and child entities associated with the relationships. Once all of the entities had been loaded and the recursion had completed and we were returned to the entry point where we started loading the entities I ask the relationship builder to resolve all the relationships. This then creates each relationship it has been informed about and sets the relationship instance on the parent and child instances which are involved in that relationship.
Related
If I have a Parent object which contains foreign key references to the Child table and I add a Child to the Parent do I need to call Context.Add() on both the child and the parent separately? or just the parent?
given that:
Parent.childobj=child;//foreign key reference set to the child object
This:
mycontext.Add(Child);
mycontext.Add(Parent);
or
mycontext.Add(Parent);
If both entities already exist and you want to relate the child with the parent, and also the parent entity is been tracked by the context, updating the FK property is enough.
Parent.ChildId=child.Id;
context.SaveChanges();
Now if Child is a new entity and parent already exist and has been tracked by the context, then use the reference property to associate both:
Parent.childobj=child; // You can also do this if both exist already in your DB
context.SaveChanges();
If both are new then add the parent to the context, that will persist also the related child:
Parent.childobj=child;
context.Parent.Add(parent);
context.SaveChanges();
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);
}
I have an intermittent problem in a production system that I haven't been able to recreate locally. What appears to be happening is that for no obvious reason during an edit of a child entity and saving the parent containing the collection the parent association on the child entity is removed in the database. Effectively orphaning the child entity.
Here is the fluent mapping:
mapping.HasMany<ExpenseItem>(x => x.ExpenseItems).Cascade.AllDeleteOrphan();
The entity can also be directly saved (it is also aggregate root), but during testing this has not be shown to remove the parent association.
There are no references to the parent itself in the child object the association is all in the DB handled by Nhibernate.
There is also no possibility of assigning the same child entity to another parent as expense item (child entity) cannot be added outside of its parent directly. See code below.
public virtual ExpenseItem AddNewExpenseItem(ExpenseAnalysis analysis,
string recipientName,
string purchaseAccountReference,
string expenseDescription,
string expenseNotes,
Money value,
VATAnalysis vat)
{
Validate.IsNotNull<ExpenseAnalysis>(analysis);
Validate.IsNotNull(expenseDescription);
....
ExpenseItem newExpenseItem = new ExpenseItem(analysis,
recipientName,
purchaseAccountReference,
expenseDescription,
expenseNotes,
value,
vat,
expenseItemUniqueReference,
true,
Candidate.Assessment);
_expenseItems.Add(newExpenseItem);
....
Any ideas?
It would definitely help to see your mapping but take a look at
I'd also map the ExpenseItem with a reference to its parent
How to delete child object in NHibernate?
basically you ve to set inverse on the relationship so that NHibernate does not try to update the deleted record with a null victim. And you set Cascade.All | Cascade.DeleteOrphans so that we aren't just breaking the relationship by nulling out the victim, but deleting the entire child record.
This problem was caused by a bug in NHibernate. I had set the session to flush never however when you call isdirty on the session the session was being flushed first. The user was deleting the expense item then cancelling the edit but during the isdirty check the deletion was being flushed. Managed to work around this by changing how the session was being managed for this type of dialog.
Is it possible to pass a reference at load time of a parent to it's children without a relationship back to the parent from the child?
I would prefer to NOT have a mapped property for this purpose (i.e. prefer not to use bi-directional relationships for this purpose).
You could probably do it with a linking table but you'd have to enforce one-to-many via code otherwise it could easily become a many-to-many. The jist of the linking table would be that it keeps the association between the parent and its children, rather than the child object itself.
Working on a project where I have more or less carte blanche to modify the database schema and object model (nice position to be in. (c:) Suppose I have a trivial inheritance tree like:
class Parent
{
public int ID { get; set; }
}
class Child : Parent
{
// some fields
}
Is it better to have a database schema where the child ID and the parent ID are the same (e.g., parent primary key is IDENTITY(1,1), child primary key is assigned and is a NOT NULL foreign key to the parent table), or should the child table maintain its own primary key and keep its reference to the parent table in another field? What are the considerations to be made in this case? What are the pro's and con's of each approach? NHibernate supports both, right?
I would let the child have it's own id. It'd be useless information but that detriment is far outweighed by the fact that it would be an easily recognizable 1-to-1 relationship rather than a "How the heck does this work?" relationship.
And yes, nHibernate can handle one-to-one relationships.