I'm trying to delete in cascade using hibernate but do not know how I can delete data with 3 tables, the first table relates to the second and the second relates to the third, but the relationship is so I have a school that has n teachers, and that teachers have n materials, any idea how can I do this?
To cascade deletion in #OnToMany associations you can either
use cascade = CascadeType.REMOVE which will delete all referencing entities
or you can add the #OnDelete(action=OnDeleteAction.CASCADE) annotation which will add an ON DELETE CASCADE clause to the foreign key definition during schema creation
Maybe you want to check also this or this related question.
Related
I've the following relationship:
class Product { // 10000s many of them
#ManyToMany
List<Category> categories; //usually 0-5
}
and
class Category {
...with no back link...
}
now if I delete a category and then I load a product that has that category I will get an error that contains:
update or delete on table "categories" violates foreign key constraint (...) is still referenced from table product_category
I've seen a number of answers and tutorials, but the problem is that many do propose to add Product as a bidirectional relationship in Category, then before removing a category I will go through all Products and remove that particular category. But products are thousands here and the operation will be too long.
This could be so simple by using normal SQL, but I'd like to keep the automatic loading of of categories and the mapping of the properties. Is there a lightweight way to automatically do this without keeping a list of products in each category?
What you're trying to do does not make lot of sense IMO.
You want to keep unidirectional relation but want a way to delete the other side directly.
But I understood that the problem was the huge dataset (category -> product).
One way to solve this would be to mix in the same transaction a JPQL(to delete the category) and a native query (to delete rows from the join-table).
em.createNativeQuery("delete from product_category where category_id = ?").setParameter(1, category.getId()).executeUpdate();
em.remove(category);
I have a JPA many to many relation.
The easiest way of deleting all entries of this relation is doing a findAll(), clearing the collection of the assoziation and flushing the session.
In my case this means loading ~1'000'000 instances into ram just to delete them all. That's not really efficient.
I could resort to SQL and simply truncate the join table. Is there an efficient way to do this in JPA?
You would need to map your m-m table as an additional entity and delete it with a delete statement. If the table is not mapped to an entity, it cannot be deleted by a delete statement. If you just want to delete the m-m relations, this should be enough. If you also wnat to delete related entities, you should map them to the new m-m entity and mark the relationship with cascade on delete.
The relation between the entities must be changed and I'd like to know is it normal to change the association mapping type and whether the data that already exist in db will be transfered normally? I tried to find information about it but didn't found. Or if the mapping will be changed the data that already exists must be transfered manually via sql queries? Thanks
If the association already uses a join table, and the mapping of the many-to-many keeps using the same join table with the same column names, you won't have to do anything except removing the unicity constraint you could have on one of the ci=olumns of the join table.
Otherwise, yes, obviously, you'll have to migrate your schema, using SQL, or any other tool (FlywayDB, Liquibase, etc.).
I could do it simply:
Let A and B be the original tables.
A->B (N-1) was moved to A<-AB->B (N-N).
I had to
- "remove" the foreignkey column from table A,
in favor of records to be inserted into AB
(made of the two foreign keys leading to A and B)
That's all.
Step one: Replace your Many-to-One annotation by your Many-to-Many annotations.
and lauch hibernate in append mode to generate the N-N table
Step two: Insert record in this N-N table given what is found in the remaining foreign-key column of you 1-N relationship.
Step three: Delete this foreign-key column.
Let's say I have two tables, employee and department where emp has a #ManyToOne key to dept. Now I want to be able to delete rows from the dept table but keep the emp records pointing to it; basically saving the relationship so that when the dept table is recreated the relationship is restored. (This actually happens in our system, but not with hibernate, but by using composed, reproducable keys).
The question is: Will hibernate crash on #ManyToOne relationships which seem to be there but with no record in the #One part of the relationship? (basically an inconsistent database state).
I probably should solve this by removing the #ManyToOne relationship and simply map the foreign key to a String or so. I just wondered whether we can pull it off to leave the relationship in place..
Now I want to be able to delete rows from the dept table but keep the emp records pointing to it;
Then you'll have to delete them logically, not physically (and FK constraints will actually prevent you from deleting departments).
Will hibernate crash on #ManyToOne relationships which seem to be there but with no record in the #One part of the relationship?
Don't you have referential integrity (see above)? But let's say you broke the integrity... Maybe you'll be able to load employees but something is going to crash at some point (when loading the association, if not before).
I probably should solve this by removing the #ManyToOne relationship and simply map the foreign key to a String or so. I just wondered whether we can pull it off to leave the relationship in place..
Delete the departments logically.
I dont really get to work with entity beans, but they are staring at me right now.
We have a couple of tables that are related to each other, but there are no foreign keys, and we cannot add any. For this question, the database cannot change, it's just not possible, but as a different solution we might create views. Anyways...
I have 3 tables.
LOCATION , LINKS and ENDPOINT and for extra salt, we a a LINKS_TYPE table.
LOCATION table has a primary key LOCATIONID which is a string containing the location id.
LINKS table has a LINKID as primary key
a column LINK_ATTR_VALUE_A which contains ENDPOINT's primary key
a column LINK_ATTR_VALUE_B which contains LOCATION's primary key.
a column LINKTYPEID which contains a LINKS_TYPE primary key
ENDPOINT table has a primary key POINTID
LINKS_TYPE has primary key LINKTYPEID
a column LINKTYPEA (text string defining the table name it's linked to)
a column LINKTYPEB (text string defining the table name it's linked to)
Now even though LINKS_TYPE is mentioned, I dont need to worry about that now, because there are no other links in this instance of the database.
I would like to define a member in my LOCATION entity 'List endPoints'
Which would be a #OneToMany from my understanding.
Do keep in mind, there is no foreign key to help here, and there wont ever be.
This is the mapping I defined...
#OneToMany ( cascade=CascadeType.ALL)
#JoinTable ( name = "ENDPOINT",
joinColumns = #JoinColumn (
name = "LINK_ATTR_VALUE_B"
),
inverseJoinColumns =
#JoinColumn (
name = "LINK_ATTR_VALUE_A"
)
)
private List<EndPoint> endPoints;
It's very likely from this you might realize I have no clue what I'm doing :D
But the documentation aint too great, and Ive ordered a book for help with ejb 3, but I just dont have the time to finish the book before this mapping :D
We are using TopLink with jdeveloper 11g and that weblogic server thing and oracle 10g as database.
When using a serviceFacade client to query, everything did seem right (since then workspace died and I have to recreate the project to get the client working).
It generates the perfect query in my opinion to retrieve the right data.
Yet, it ends with no results.
I'm willing to give as much info as possible, just not sure what is needed.
But I know my mapping is most probably wrong, and it's because I do not understand the mapping.
Could someone help me?
Thank you.
Your LINKS table looks like many-to-many mapping table between LOCATION and ENDPOINT rather than one-to-many. The big question here is whether it has any additional columns aside from LINKID, LINK_ATTR_VALUE_A and LINK_ATTR_VALUE_B that you listed?
If it does, then you would have to map it as a separate entity:
Location would have a collection of Links mapped as bi-directional one-to-many
Link would have many-to-one relationships with both Location and EndPoint
If, OTOH, LINKS has no other columns AND you're willing to forgo its primary key (which is neither needed nor can be mapped for many-to-many join table) then you can map it as many-to-many collection of EndPoints on Location.
If you can clarify your question I'll update my answer to include the actual mapping if you need it.
Here is the mapping I ended on.
#OneToMany(cascade=CascadeType.ALL)
#JoinTable(name = "LINK",
joinColumns = {
#JoinColumn(name="LINK_ATTR_VALUE_B")
},
inverseJoinColumns = {
#JoinColumn(name="LINK_ATTR_VALUE_A")
}
)
private List<EndPoint> endPoints;
There just isnt truly any values needed right now in the LINK table.
But when it' time, our DBA's will need to create materialized views for us or something.
But when attemting the mapping, I initialy kept the LINK, rather than going straight to the endPoint. I was being returned 5000+ links where there should only be 133. So again there is a mapping I dont understand,but I'll leave that for later.
At the moment our database only contains 1 link type. This will change, and I really which there was a way for me to add an additional where clause to the mapping, so I could have different attribute mappings for different types.
I'm in a typing mood today :-D