Maybe it is a really stupid question but I just can't find solution. I have:
#OneToMany(mappedBy = "project", fetch = FetchType.LAZY)
private List<Comment> comments;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "project_id")
private Project project;
When I launch application, I retrieve all comments by getter (it is loaded properly). When I however delete/add another comment, database is updated but application is not until rerun. When creating comment it is persisted - it is in DB - so I do not understand how is it not updated. Tried various cascade types but I do not think it is necessary here anyway. I also tried EAGER and it does not work as well.
When I manually get comments from DB after adding/deleting it works but that is I think very dirty solution right?
Thanks for any suggestions.
You have to fetch that entity you pasted a piece of code of once again. Already fetched list will not magicly update itself.
Its like using SQL - you have rerun the query to see the updates. ORM just maps SQL results row into objects.
Related
entity = MainDao.findByUUID(getEntityManager(), dto.getUuid());
Adress i = new AdressDao().findById(dto.getIdAdress());
i.setPhone(dto.getPhone());
entity.setAdress(i);
return MainDao.update(getEntityManager(), entity);
I have a main Entity in which there is a #ManytoOne relationship to Adress. I want to update the field "phone" inside adress, how do I do it? My code fails to do so.
Hope you can help me out, it seems there is no "patch" method inside JPA. I would love to know the best practices.
By default #ManyToOne doesn't cascade the changes (as it refers to a parent which may be have other child associations).
You can do either of below,
save the changes of Address entity via your AddressDao like addressDao.save(addressEntity)
use #ManyToOne(cascade = CascadeType.ALL).
1st options is preferable.
Read about CascadeType to utilize wisefully.
I am yet again stuck with trying to delete data with Hibernate..
I am at point where I am starting to just stack annotation, hoping something would work... so far nothing has.
I need to delete old calculation when starting new for same time period.
I have the following query
#Modifying
#QueryHints(value = #QueryHint(name = HINT_FETCH_SIZE, value = "10"))
#Query(value = "DELETE FROM Group a WHERE a.c_date BETWEEN :dateA AND :dateB")
void deleteOld(#Param("dateA") LocalDate dateA, #Param("dateB") LocalDate dateB);
which uses entity Group, which has (on top of normal String, LocalDate and long types) attribute
#OneToMany(cascade=CascadeType.ALL, mappedBy = "owner", orphanRemoval = true)
#JsonManagedReference
#OnDelete(action = OnDeleteAction.CASCADE)
private List<Instrument> instruments = new ArrayList<>();
But I still get violated - child record found every time I try to run delete method.
I keep finding more and more annotations like this, from threads where people have the same kind of problems, but I would love to understand why is this a problem. From what I read Cascade and orphanRemoval should be all I need, but it sure does not seem to be.
Hibernate: 5.2.17.Final
Please help me to understand, why is this happening ?
The #OnDelete will delete records using a ON DELETE rule on the database, when using Hibernate to generate the schema. If you manage your own schema this will have no effect.
The #QueryHints you have specified doesn't really make sense here, for an DELETE query that is. Nothing will be fetched.
The fact that you are using an #Query basically bypasses the configuration in the #OneToMany, simply due to the fact that you write a query and apparently know what you are doing. So the mapping isn't taken into account.
If you want to delete the childs as then you have 3 options:
Add an additional query and first remove the childs, then the parents
Add an ON DELETE rule to your database, to automatically remove the childs
Retrieve the Group and remove using EntityManager.remove which will take the #OneToMany mappings into account as now Hibernate needs to manage the dependencies between the entities.
I have 2 classes in java with relation parent-child and I have a problem with the delete child. when I delete a child the function return true but when I check database nothing happens, the child still not deleted.
this is my class parent : Engagement.java
#OneToMany(fetch=FetchType.EAGER, mappedBy="parent", cascade=CascadeType.ALL)
private Collection<Sub_Engagement> subs_engs;
this is my class child: Sub_Engagement.java
#ManyToOne
#JoinColumn(name="parent")
private Engagement parent;
with this code POST/GET/PATCH work fine but DELETE not working.
I tried a solution like that:
#OneToMany(fetch=FetchType.EAGER, mappedBy="parent", orphanRemoval = true, cascade = { CascadeType.MERGE, CascadeType.REFRESH, CascadeType.DETACH, CascadeType.REMOVE})
private Collection<Sub_Engagement> subs_engs;
and DELETE works but PATCH/PUT not working when I try update a child.
Thanks in advance :)
Andronicus had it right, that really should work. It's weird that you have an either-or situation with you updates and deletes.
Double check your persistence.xml. Is there something that overrides the annotations?
I also recommend to enable tracing and check the sql queries actually executed. Is the delete statement logged? Is your transaction actually committed?
Can we look at the code you are using for removing the entities? Are you using entitymanager's remove() method or executing some custom jpql?
Also, are you using a CMT (for example EJBs) or are you handling the transactions yourself via JTA?
I've got this structure of project:
class UserServiceSettingsImpl {
...
#ManyToOne
private UserImpl user;
#ManyToOne
private ServiceImpl service;
...
}
class ServiceImpl {
....
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "service", orphanRemoval = true)
private Set<UserServiceSettingsImpl> userServiceSettings;
....
}
class UserImpl {
....
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "user", orphanRemoval = true)
private Set<UserServiceSettingsImpl> serviceSettings;
....
}
I am trying to delete Service and everything that belongs to it (UserServiceSettingsImpl), but accidentally, this settings are not being removed (I suppose because they are not orphans since UserImpl has them too). So the thing is: is there a way to delete Settings, without deleting them from user manually (there could be a lot of users with a lot of settings, iterating through it could take a lot of time) ?
You are correct in why the UserServiceSettings are not being deleted when deleting a service if they are also referenced by a User. They are not orphans and will have to be deleted explicitly per your business logic.
Three ideas:
Use the ORM to batch delete entities.
It's not much different than iterating, but might be optimized while still using the ORM.
List settingsCopy = new ArrayList<>(service.getSettings());
service.getSettings().clear();
myDao.deleteAll(settingsCopy);
Use direct HSQL/SQL to batch delete.
This depends on what framework you are using, but generally would be something like this, probably in your repository/dao class:delete from UserServiceSettingsImpl o where o.service.id = ? However, hibernate does not support JOINs when deleting, afaik, so this doesn't work as written. It's generally necessary to rework the HSQL to use a "delete where id IN(...)" type format.
Setup CASCADE DELETEs and CASCADE UPDATEs in your database DDL, outside of the ORM framework. (Not recommended.)
However, the last two options have problems if there is chance that service's and user's UserServiceSettings can be modified at same time via multiple threads (even with correct transaction boundaries), or if those entities will be used within the orm context after the delete without a reload. In that case, you will likely run in to unexpected and sporadic errors with the last two approaches, and instead, should iterate the settings and delete via the ORM, even if it is inefficient.
Even with the first approach, it can be tricky to avoid errors in highly concurrent environments when deleting shared entities.
You're correct that you cannot delete them in any kind of automatic way - they will never be orphans. I think the best you can do is just write yourself a helper method. e.g. if you have a ServiceDao class, you would just add a helper as:
public void deleteServiceAndSettings(Service service) {
for (UserServiceSettings setting : service.getUserServiceSettings()) {
session.delete(setting);
}
session.delete(service);
}
I am trying to refresh the #ManyToMany relation but it gets cleared instead...
My Project class looks like this:
#Entity
public class Project {
...
#ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinTable(name = "PROJECT_USER",
joinColumns = #JoinColumn(name = "PROJECT_ID", referencedColumnName = "ID"),
inverseJoinColumns = #JoinColumn(name = "USER_ID", referencedColumnName = "ID"))
private Collection<User> users;
...
}
But I don't have - and I don't want - the collection of Projects in the User entity.
When I look at the generated database tables, they look good. They contain all columns and constraints (primary/foreign keys).
But when I persist a Project that has a list of Users (and the users are still in the database), the mapping table doesn't get updated gets updated but when I refresh the project afterwards, the list of Users is cleared.
For better understanding:
Project project = ...; // new project with users that are available in the db
System.out.println(project getUsers().size()); // prints 5
em.persist(project);
System.out.println(project getUsers().size()); // prints 5
em.refresh(project);
System.out.println(project getUsers().size()); // prints 0
So, how can I refresh the relation between User and Project?
The error seems to be in the code that you left out with ...
I am assuming that project actually did come out of the database (making persist a noop), otherwise you should be getting a hibernate exception when you try to refresh an entity that hasn't been committed yet.
There seems to just be some confusion here about the difference between JDBC and ORM and what an EntityManager actually does. em.persist is not a SQL insert or a SQL update. It says 'take this new entity and put it in the managed state.' Usually that eventually leads to a SQL insert, but that's not what it means at the application level.
It looks like you're essentially telling hibernate "I made some changes to this, next time the session is synchronized please persist them, oh, you know what, I changed my mind, revert back to what's in the database." em.persist does not directly put anything in the database, what's there is probably still "nothing".
Try tossing an em.flush in before your refresh and you should see your Users.
(You haven't said anything about how your session is configure or how you're managing transactions, so I'm assuming all of this is in one transaction.)