Delete in HasManyToMany - nhibernate

I have three table -
1. Anomaly
2. Markup
3. Anomaly_Markup
Mapping -
public AnomalyMap()
{
Table("anomaly");
Id(x => x.Id).Column("ID").CustomType("decimal");
HasManyToMany<DMMarkupData>(x => x.DMMarkupData)
.Table("anomaly_markup")
.ParentKeyColumn("ANOMALY_ID")
.ChildKeyColumn("MARK_UP_ID")
.Cascade.All()
.LazyLoad();
}
public MarkupDataMap()
{
Table("markup");
Id(x => x.Id).Column("ID");
}
Condition :
Save data by Anomaly - Anomaly contains MarkupData. It saves data. It is working functionality with me.
Delete markup - which should delete relationship from map table and markup data. I am facing this issue.
Anyone help me to find out solution, how to delete markup data ?

I see no relationship of MarkUpData with Anomaly. There must be same relationship and you should specify the control of cascade operation by using Inverse attribute in your mapping.
You can refer : How to set "cascade delete" option to "Set Null" in Fluent NHibernate?
To delete DMMarkupData just remove the object from collection and call for Save Anomaly.

From what you've posted it looks like you haven't defined a relationship on DMMarkupData -> Anomaly, so NHibernate won't know to delete it the MarkupData entries from the anomaly_markup table (despite the reverse relationship being there). You can either solve it with a database level cascade which removes entries in anomaly_markup when deleting MarkupData, or you can map the relationship in code & NHibernate and then NHibernate will do the cascade for you.

NHibernate does not manage the object graph, it only persists it. Removing the item from the list when it gets deleted is responsibility of the business logic!
(All the tricks with triggers and stuff that workaround it lead to inconsistencies and side effects within the transaction which does the change. From point of view of persistence ignorance it is not recommended. I would only do it when facing performance issues that can't be solved in another way.)
You can simplify it by using components. Provided that
you don't reference the same markup from somewhere else
you don't need to query for markup unrelated to Anomality
markups do never live outside of an Anomality
given all that, it is much easier to work with components. (I don't know how it is called in fluent, but in xml mapping it is called a "composite-element").
When using components, you don't need to delete the markup from the database. You just remove it from the list where it lives in.

Related

Fluent NHibernate One-To-Many Cascade Delete if Many-Side is not referenced anywhere else

I have a working solution but would be interested to know if there is a way to achieve this through fluent mapping..
For simplicity, I will use a illustrative example:
class Tag {
string name;
IList<Book> books;
}
class Book {
string title;
Tag primaryTag;
}
There is a business case, where Books are deleted and right now, I query the db to check if any other book references the current tag as primary. If not, I delete the book and after that, I delete the tag because it is not used anywhere else. If the tag is stil used, I only delete the book.
Now it's your turn... do you know a way to achieve this using mappings? I tried the following:
BookMap : ClassMap<Book> {
...
References(x => x.primaryTag)
.Cascade.All() //the collection in TagMap is set to "inverse"
}
But not surprisingly, it throws a foreign key constraint error when the tag is used in other books.
Regards,
Martin
There's no way to do that. NHIbernate is mimicking what you can do in Sql Server config with cascade-deletes. There's no way to go up to a parent and delete "orphans" without using triggers in Sql Server.
There's a way to mimic triggers in NHibernate using "Interceptors" - a way to listen for CRUD on specific Entities and then perform actions. But really it's an anti-pattern since you may as well add the same code to the method that removes the Tag (rather in some hidden/obscure approach like the following, which is usefull for cross-cutting concerns such as Auditing).
This is a really nice article on how to do it (but there's loads out there just google "NHibernate Interceptors").
I'd make sure to use Session.Delete(entity) to ensure deleted entities are removed from Session (for sanity) rather than

NHibernate One-to-Many - why is it updating child with null foreign key?

I am troubleshooting code that is attempting to update a disconnected entity that has uninitialized references to child entities. The intent is to update only the properties on Parent without loading children.
HasMany(x => x.ChildEntities)
.KeyColumn("ChildEntityId")
.Table("ChildEntity")
.Not.LazyLoad()
.Inverse()
.Cascade.All().AsBag();
When Session.Update(parent) is called, two update statements are executed. The first updates the parent object as expected.
update Parent set ... where ParentId = 12345
The second update confuses me...
update ChildEntity set ParentId = null where ParentId = 12345
Why is NHibernate issuing that second SQL statement? I realize that ChildEntities is uninitialized and that NHibernate is probably trying to enforce the state of Parent but I can't seem to tweak the mapping to not make this second update. I've tried Merge, lazy loading, various cascade options, etc. without success. The only connected entity in the session when it tries to commit is Parent.
Note that I typically approach this by retrieving the entity with lazy loading enabled and then mapping from the disconnected object (DTO or entity) to the connected entity before letting NHibernate persist to the database. I want to understand why the above isn't working before I suggest an alternative approach.
This was annoying.
A quick search through the NHibernate source for "could not delete collection" showed up in a block that could only execute if !isInverse (AbstractCollectionPersister.cs). That drew my attention because the mapping code was explicitly setting Inverse on that collection.
If Inverse is false and the collection is empty, NH executes an update on the child table setting the foreign key to null where the foreign key equals the parent id.
Fluent is configured to auto-map all entities in a given namespace. The assumption was that anything with a manual mapping would be ignored by auto mapping. A quick check of the hbm.xml files produced by Fluent confirmed that Inverse was not being set. I added Parent to the list of entities that were explicitly excluded from Auto Mapping and everything started working.
.IgnoreBase<Parent>()

FluentNHibernate Where clause does not appear to be used when populating collections

I use a Where clause in my FluentNHibernate mappings as follows:
public class FooMap : ClassMap<Foo>
{
public FooMap()
{
Table("MySchema.Foos");
Where("Deleted = 0");
etc etc
}
}
This where clause gets appended to the SQL when I load individual Foo instances through session.Load<Foo>(1) and when I use LINQ queries. However, if another class has a collection of Foos and I iterate through the collection, the SQL generated to load the Foos does NOT contain the where clause.
Is this a bug in FluentNHibernate, or NHibernate in general? Or am I doing something wrong? Or is it (shudder) a 'feature'?
It's a fact, I don't know if it's a bug, a feature, or a missing feature. I ran into the same issue with a legacy database, although mine was with a many-to-one relationship (a "god" lookup table).
I think the justification is that once the foreign-key relationship has been established then the where clause has no meaning. For soft delete tables, look into using filters or (my preference) map to a view that filters the deleted records, assuming they don't need to appear in the UI.

Why doesn't NHibernate delete orphans first?

I'm trying to figure out why NHibernate handles one-to-many cascading (using cascade=all-delete-orphan) the way it does. I ran into the same issue as this guy:
Forcing NHibernate to cascade delete before inserts
As far as I can tell NHibernate always performs inserts first, then updates, then deletes. There may be a very good reason for this, but I can't for the life of me figure out what that reason is. I'm hoping that a better understanding of this will help me come up with a solution that I don't hate :)
Are there any good theories on this behavior? In what scenario would deleting orphans first not work? Do all ORMs work this way?
EDIT: After saying there is no reason, here is a reason.
Lets say you have the following scenario:
public class Dog {
public DogLeg StrongestLeg {get;set;}
public IList<DogLeg> Legs {get;set;
}
If you were to delete first, and lets say you delete all of Dog.Legs, then you may delete the StrongestLeg which would cause a reference violation. Hence you cannot DELETE before you UPDATE.
Lets say you add a new leg, and that new leg is also the StrongestLeg. Then you must INSERT before you UPDATE so that the Leg has an Id that can be inserted into Dog.StrongestLegId.
So you must INSERT, UPDATE, then DELETE.
Also as nHibernate is based on Hibernate, I had a look into Hibernate and found several people talking about the same issue.
Support one-to-many list associations with constraints on both (owner_id, position) and (child_id)
Non lazy loaded List updates done in wrong order, cause exception
wrong insert/delete order when updating record-set
Why does Hibernate perform Inserts before Deletes?
Unidirection OneToMany causes duplicate key entry violation when removing from list
And here is the best answer from them:
Gail Badner added a comment - 21/Feb/08 2:30 PM: The problem arises when a new
association entity with a generated ID
is added to the collection. The first
step, when merging an entity
containing this collection, is to
cascade save the new association
entity. The cascade must occur before
other changes to the collection.
Because the unique key for this new
association entity is the same as an
entity that is already persisted, a
ConstraintViolationException is
thrown. This is expected behavior.

Restricting deletion with NHibernate

I'm using NHibernate (fluent) to access an old third-party database with a bunch of tables, that are not related in any explicit way. That is a child tables does have parentID columns which contains the primary key of the parent table, but there are no foreign key relations ensuring these relations. Ideally I would like to add some foreign keys, but cannot touch the database schema.
My application works fine, but I would really like impose a referential integrity rule that would prohibit deletion of parent objects if they have children, e.i. something similar 'ON DELETE RESTRICT' but maintained by NHibernate.
Any ideas on how to approach this would be appreciated. Should I look into the OnDelete() method on the IInterceptor interface, or are there other ways to solve this?
Of course any solution will come with a performance penalty, but I can live with that.
I can't think of a way to do this in NHibernate because it would require that NHibernate have some knowledge of the relationships. I would handle this in code using the sepecification pattern. For example (using a Company object with links to Employee objects):
public class CanDeleteCompanySpecification
{
bool IsSatisfiedBy(Company candidate)
{
// Check for related Employee records by loading collection
// or using COUNT(*).
// Return true if there are no related records and the Company can be deleted.
// Hope that no linked Employee records are created before the delete commits.
}
}