Can a collection in NHibernate be mapped as read-only? - nhibernate

I have a mapping defined where a parent object has a collection of child objects. In my design, I'd like to be able to delete the child objects without having to remove them from the collection on the parent object and re-saving the parent object. However, when I try this, I get the "deleted object would be re-created on save" error. Is there a way to prevent this such that I could simply delete the child object and not worry about removing it from the parent's collection too? That feels like doing double the work. Ideally I'd like to treat the parent's collection as read-only from NHibernate's perspective.

It'd help if you post your mapping files, but it sounds like you need to add Inverse=true to the collection mapping. This means that the child object is responsible for handling any save or updates, not the parent.
However, in the database it's all modelled the same. The child should have a column for the parent row's ID. NHibernate will create different SQL based on the Inverse property though. I'd like to give more detail, but I'm learning NHibernate myself as well.

I believe the only thing you need to do is just set the collection of child objects in the parent's mapping file to be cascade="none".
Of course that will also prevent saving child objects by assigning them to the parent's collection and updating the parent. If that is OK then you got your solution.

Related

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

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.

When can I use Unidirectional relationships in 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.

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

NHibernate collections and moving objects

I just ran into a major issue for me with NHibernate. I have 2 objects, each with a collection of things. I need to move one thing from the collection from Object A to the collection of Object B. I get an error about a deleted object because, I believe, NHibernate attempts to delete the thing from the collection of Object A when it needs to keep it for Object B.
From a DB standpoint, it's just a matter of updating the "parent" property to the new object (Object B). But with the collections, I am not really sure what do to...
Is there a well-known procedure to move objects from one collection into another one in NHibernate?
Thanks in advance for any help.
Regards,
Eric.
I'm assuming that you are using Cascade in the mapping for the class represented by objects A and B, i.e., A and B are both instances of some class X, and X's mapping contains a cascade attribute on the collection containing the object to be transferred.
Given that assumption, this may help.
If you want to be able to transfer the object from one collection to the other, you need to consider whether the thing that is being moved should have an existence that is independent of the two collections.
If the transfer object doesn't get saved on its own, you will run into problems when you do the transfer because the transfered object is already known to the session.
There are two ways out that I can think of. The better of the two is probably to treat the transfer object as an independent object which is saved on its own to the db (i.e, doesn't rely on Cascading in the mapping of the objects with the collection). Conceptually, this makes sense because if you can transfer it from one collection to the other that implies that somehow it is independent of the two objects having the collections. It does mean that you could end up with orphans.
If you want to stick with using cascade in the mappings, then you will need to remove from object A in a different transaction than the add to object B. I suspect that isn't what you want to do.
Have you tried mapping using
cascade="all-delete-orphan"