One to one composition vs. one to one association - cuba-platform

I have a customer with an address. The address should be deleted if the customer will be deleted. In my opinion it is a composition. But compositions in cuba are only one to many.
I solved it with in one to one association and the cascade type ALL:
#OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
protected address
Is this the way I have to go?

You are right, currently the #Composition annotation affects only the way how editors work for one-to-many relationships. Editing of one-to-one relationships will be covered in a future release, it's on our roadmap.
For cascade deletion we recomend the following approach:
If the master entity implements SoftDelete, use #OnDelete(DeletePolicy.CASCADE) annotation on the detail attribute
Otherwise, use ON DELETE CASCADE in your foreign key definition - it can be added manually to init/update scripts

Related

How can these constraints may cause cycles or multiple cascade paths?

Note: this question is more about database design and SQL Server than specific ORMDB like EF Core.
I have a database schema that looks like this:
Using EF Core Migration, all the SQL statements can be run until the very last constraint (FK_BookReleases_Nicknames_NicknameId). The previous FK FK_BookReleases_Books_BookId could be added.
The error I receive is (as many other articles on SO):
Introducing FOREIGN KEY constraint
'FK_BookReleases_Nicknames_NicknameId' on table 'BookReleases' may
cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or
ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
My question is, where is the flaw on that design? I cannot understand under any logic such situation happens. And what is the proper fix? I see many suggested changing ON DELETE action but not specific on which FK and what other action I should use.
Worse, even already read this article I still don't understand how it could be a problem, and how would his proposed solution fits in the above schema.
The issue is due to multiple cascading paths from Author (Grand Parent) to BookRelease (Grand Child). There are two cascading paths:
Author -> Book -> BookRelease
Author -> Nickname -> BookRelease
This is discussed in detail in the post in MSSQLTips
So, the way to handle this is:
Disable the ON DELETE CASCAE and choose NOACTION as the foreign key creation.
Create INSTEAD OF DELETE TRIGGERS in Author(GrandParent), Book(Child1), Nickname(Child2) tables to handle the deletion of parent keys in the child tables.
Grand Parent deletion : Delete in GrandChild, followed by Child1,
followed by Child2,
Child1 deletion: Delete in GrandChild, followed
by Child1
Child2 deletion: Delete in GrandChild, followed by Child2

Should I let JPA or the database cascade deletions?

Let's say we have two entities, A and B. B has a many-to-one relationship to A like follows:
#Entity
public class A {
#OneToMany(mappedBy="a_id")
private List<B> children;
}
#Entity
public class B {
private String data;
}
Now, I want to delete the A object and cascade the deletions to all its children B. There are two ways to do this:
Add cascade=CascadeType.ALL, orphanRemoval=true to the OneToMany annotation, letting JPA remove all children before removing the A-object from the database.
Leave the classes as they are and simply let the database cascade the deletion.
Is there any problem with using the later option? Will it cause the Entity Manager to keep references to already deleted objects? My reason for choosing option two over one is that option one generates n+1 SQL queries for a removal, which can take a prolonged time when object A contains a lot of children, while option two only generates a single SQL query and then moves on happily. Is there any "best practice" regarding this?
I'd prefer the database. Why?
The database is probably a lot faster doing this
The database should be the primary place to hold integrity and relationship information. JPA is just reflecting that information
If you're connecting with a different application / platform (i.e. without JPA), you can still cascadingly delete your records, which helps increase data integrity
In EclipseLink you can use both if you use the #CascadeOnDelete annotation. EclipseLink will also generate the cascade DDL for you.
See,
http://wiki.eclipse.org/EclipseLink/Examples/JPA/DeleteCascade
This optimizes the deletion by letting the database do it, but also maintains the cache and the persistence unit by removing the objects.
Note that orphanRemoval=true will also delete objects removed from the collection, which the database cascade constraint will not do for you, so having the rules in JPA is still necessary. There are also some relationships that the database cannot handle deletion for, as the database can only cascade in the inverse direction of the constraint, a OneToOne with a foreign key, or a OneToMany with a join table cannot be cascaded on the database.
This answer raises some really strong arguments about why it should be JPA that handles the cascade, not the database.
Here's the relevant quote:
...if you would make cascades on database, and not declare them in
Hibernate (for performance issues) you could in some circumstances get
errors. This is because Hibernate stores entities in its session
cache, so it would not know about database deleting something in
cascade.
When you use second-level cache, your situation is even worse, because
this cache lives longer than session and such changes on db-side will
be invisible to other sessions as long old values are stored in this
cache.

Unable to cascade delete a #OneToOne member

#Entity public class Organization {
#OneToOne(fetch = FetchType.EAGER)
#OnDelete(action = OnDeleteAction.CASCADE)
#Cascade(value = DELETE_ORPHAN)
private Days days;
}
I have the following entity definition and it generates a SQL to do a cascade delete on the #OneToOne entry when the parent object gets deleted. But it's not removing the "days" entry while deleting an Organization.
This happens with h2, mysql databases, what could be the problem here.
My query looks like this "delete from Organization where some_key_id = ?" (am not deleting this based on primary key id)
A bulk delete (you should mention that in your question) doesn't cascade to anything. Quoting the JPA 1.0 specification:
4.10 Bulk Update and Delete Operations
...
A delete operation only applies to
entities of the specified class and
its subclasses. It does not cascade to
related entities.
This is a very annoying limitation and there are many RFEs to improve things (HHH-695, HHH-1917, HHH-3337, HHH-5529, etc).
For now, possible solutions include:
clean up the child table yourself
use cascading foreign keys in the schema.
Now the weird part... My understanding of #OnDelete(action = OnDeleteAction.CASCADE) is that this annotation is supposed to be used to ensure that the foreign key is created with the appropriate ON DELETE CASCADE clause (solution #2). In other words, I'd expect things to work.
Did Hibernate generate the Organization table? Can you check the DDL? Do you see the expected ON DELETE CASCADE? If not, add it.
Well, I guess you should add a
#Cascade(value = {DELETE, DELETE_ORPHAN})
Note that in JPA 2.0 you don't have to use the hibernate-sepcific #Cascade annotation - #*ToMany has an option to delete orphans.
Update: when using queries cascades are not handled. You have to handle them manually. This is expected and documented behaviour.

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.
}
}