When can I use Unidirectional relationships in NHibernate? - nhibernate

I'm trying to port a large graph of .NET entities to use NHibernate, but I'm encountering an issue that most of the relationships are only defined unidirectionally - in most cases, the child class contains a reference to the parent, but the parent does not contain the collection of refs to its children. It would be quite a bit of work to add all the collections to turn the relationships into bidirectional ones, so I'm wondering what the consequences for NHibernate would be of not doing so?
One consequence I've noticed is that cascading deletes seem to fail (child doesn't get deleted in the DB, causing a referential integrity violation). Is that the only consequence or are there other issues I need to be aware of?
Are there any guidelines for when relationships should be uni or bi-directional?
Thanks

I think that not being able to cascade the deletes will be the only issue with NHibernate per se.
But you will not be able to easily walk the graph. You can do it from child to parent, but obviously not from parent to child. So you would have to issue a query each time you want all the childs from a parent.
So if you are using NH for a persisted domain model, where you have a root object from which you need to use the child objects for certain operations, you would have to issue queries from within the model to get the children. So your model will be coupled to your data access.
Or you would have to pass the children to the parent object as collections, but then it might be just at easy to have the collections on the model to begin width so NH could fill them for you.

Related

Will NHibernate SaveOrUpdate be able to work thru entity's related objects as well?

I have an NHibernate entity that has 2 relationships of many to many.
Suppose I have a detached version of this entity, will SaveOrUpdate be able to decide Saving or Updating thru the related objects as well?
It depends on how relationship is configured.
The main things that come to mind are cascading and whether it is inverse or not.
If you want things to automatically cascade (~work thru) then just set that in you hbm collection association node
cascade="all"
There are more cascading options worth reading and understanding

Fluent NHibernate - avoid loading children collection

I have 2 classes with HasMany relationship, say a class called Parent that has a collection of Children. I want to be able to build queries in NHibernate that would only return Parents that have Children. I guess that to do that I need to have this HasMany relationship.
What I want though is following - when I load Parents, I don't want it's children to be loaded. Kind of LazyLoading, but without loading Children at all.
Any ideas how to accomplish this?
NHibernate's LazyLoading of collections is exactly what you asked for. The collection-object itself is created but none of the child objects is loaded.
When JSON method is called Children objects are loaded lazily. I want to avoid it.
3 Options come to mind
projecting the Parentobject into a DTO which is then serialized
Customizing the JSON serialization
detaching the parent from the session (Evict()) and setting the collection to null before serializing
i would favor option 1, but option 2 would be ok too. Option 3 would be a hack and should be avoided

Unidirectional parent-child association not null

I have a class structure which is akin to a PurchaseOrder (parent) and PurchaseOrderLine (child) pattern, where the order lines will only be saved to the DB by saving the parent PurchaseOrder and will only ever be accessed via the parent too.
The DB has PurchaseOrderLine.PurchaseOrder set to not permit null values.
It seems from searching through the web that it is not possible to have a uni-directional association from PurchaseOrder via an IList property without having to have a property on the line pointing back when the child has a NOT NULL constraint for its PurchaseOrder column.
Is this really the case? It seems like one of the most basic things one would want to do with an ORM, I find it difficult to accept that a product as mature as NHibernate cannot handle such a basic scenario.
No it's not the case. Please see the example provided in the answer to this question: When to use inverse=false on NHibernate / Hibernate OneToMany relationships?
Well, it may be the case that you can't have unidirectional one-to-many relationship defined only on one side, but I'll argue with your statement that this is "one of the most basic things one would want to do with an ORM".
One of the most basic things would be to have unidirectional one-to-many defined only on many side - as it is natural for RDBM tables. And ORMs (despite the common misconception) are not intended (or able) to fully abstract domain model from underlying data source. Even if in some cases they can, the database side suffers from select N+1 problems or very ineffective queries.
Defining one-to-many at one side makes an impression that i.e. counting the collection is cheap. It is the case with plain object graphs, but not with NHibernate entities, as reading collection causes (at least one) call to the database. Eager fetching from one side is also not able to properly use database join mechanism in the way it's intended to be used (opposite to eager fetch from many side).
Even if I don't agree with a lot of arguments, I think it is useful to read some of the articles saying that "ORM is an anti-pattern", like this one. They helped me to leverage the way I think about ORMs and make me think about ORMs as a compromise between two not matching paradigms, but not the way to hide one behind another.
This can now be achieved in NH3 using the Not.KeyNullable()
this.HasMany(x => x.Actions)
.Access.BackingField()
.KeyColumn("[Application]")
.Not.KeyNullable()
.Cascade.AllDeleteOrphan();

NHibernate: removing from collection vs association and cascading styles

I'm having trouble understanding how NHibernate knows anything about objects removed from association (and then execute cascading style like delete-orphant). I mean, at a database level if I wanted to remove an association I'd have to physically log on and remove some FK. How does this happen in NH world? Do I remap my classes, remove previously established parent/child association (relationship), NH does comparative analysis, digs that something has been changed and then takes appropriate action? In this post Ayende talks about different cascading styles and delete-orphat is described as "... In addition to that, when an object is removed from the assoication and not assoicated with another object (orphaned), also delete it ..." How does this removal happen?
NHibernate watches all the mapped collections mapped that are owned by objects in the NHibernate session. As you make changes (adding/removing) NHibernate marks them as dirty. When it is time to flush the changes it compares the elements in the dirty collections and is able to identify what items have been added and removed. Depending on the cascade options for the collection NHibernate might then persist those changes to the database.
This is why you should always declare collection properties using interfaces (IList, ISet, etc.) and never replace a collection property on an object that has been loaded using NHibernate.
Additional info requested in comments:
There is a useful discussion by Fabio Maulo (NHibernate lead developer) of collection mapping here which I would strongly recommend to read. But to try and provide a brief answer to your questions:
But how does NH know that association between objects has been removed?
Generally when working in the OO model with many associations we manage relationships at the parent. That is, a child is considered to be associated with the parent when it is in a parent's collection. E.g.
child.Parent = parent;
parent.Children.Add(child); // This is the critical bit
session.Save(parent); // to have an INSERT generated here
Similarly removing an item from a collection breaks the association (assuming correct mapping attributes have used)
child.Parent = null;
parent.Children.Remove(child); // This is critical bit
session.Save(parent); // To have DELETE or UPDATE statement generated depending on cascade settings.
This is the opposite of how things work in the relational world where we manage the relationship at the child via the foreign key on the child row.
For a more detailed understanding there is nothing like downloading the NHibernate source code, creating a simple test case and then stepping through in the debugger.
What's the reason behind the "This is why..."
There are a number of things NHibernate takes care of in managing in association collections. It does this by using its own collection classes that keep track of whether they are dirty, what state they were in when they were loaded from the db and a number of other cool things. If you replace those objects then NHibernate loses that capability. So, for instance if you want to get rid of all the items in a collection you should do:
parent.Children.Clear(); // The collection object is preserved and NHibernate knows you want them all deleted.
You should NEVER do:
parent.Children = new List<X>(); // NHibernate will not track changes to this collection.
For further reading you might also want to take a look at this.

Cascading in (N)Hibernate, which rules do I need?

Sorry if this is a dupe, couldn't find it but didnt really know what to search for, anyway...
I have three classes, Parent, Child and Other
Parent has many Child where child has a Parent_Id column
Other holds a reference to a Child through a Child_Id column
When I delete a Parent, I also want to delete all the associated Child objects. If these Child objects are referenced by any Other classes, I want their (the Other objects) Child_Id references to be nullified.
What cascade rules do I need on the two relationships?
Also, will NHibernate update entities in-memory as well as in the database?
I.e. if I have a bunch of Parent, Child and Other in memory (i.e. loaded from db, not transient) and tell NH to delete a Parent, what will happen? I assume the Parent and Child objects will become transient? What will happen to the Child property of any Other objects?
Edit: when using All-Delete-Orphan, what classes an object as an orphan? In the example above, is a Child an orphan if its parent Parent is deleted? Does the reference from Other matter when considering an entity as orphaned?
Thanks
NH does not update any of your entities in memory (except of Ids and Versions). NH is not responsible to manage the relations of you entities. It just persists what you did in memory to the database.
From this point of view it should become easier to understand.
cascade="delete" means that when the parent is deleted, the child gets deleted as well.
cascade="delete-orphan" means, that additionally, the child is even deleted if no parent references it anymore. This, of course, only works if the child is in the session.
The deleted instance gets transient in memory. References to the transient instance (from Other) will cause an exception. AFAIK, you need to remove reference to deleted instances by yourself. You probably can make it implicit by some tricks, but I doubt that this will be clean. It's business logic.
For parent-child relations, cascade="all-delete-orphan" is appropriate.
For regular reference I prefer cascade="none".
There is a great explanation by Ayende Rahien