Java JPA EclipseLink ManyToMany INSERT - java

I have the following ManyToMany association within my Project:
Class User:
#ManyToMany(cascade=CascadeType.ALL)
#JoinTable(
joinColumns={#JoinColumn(name="user_id")},
inverseJoinColumns={#JoinColumn(name="antrag_id")}
)
private List<Antrag> antraege;
And Class Antrag:
#ManyToMany(mappedBy="antraege",cascade=CascadeType.ALL)
private List<User> users;
I am trying to correctly insert a new record, this - I think works not correctly. When I'm trying to "reselect" all Antraege of User, I am getting a NullPointerException on antraege.getUsers(). Only when I restart the java swing application, antraege.getUsers() doesn't return null.
Code for Inserting my new ManyToMany record:
Antrag antrag = new Antrag();
antrag.setBetreff(betreff);
antragBusiness.create(antrag);
betreuer.getAntraege().add(antrag);
currentUser.getAntraege().add(antrag);
userBusiness.update(betreuer);
userBusiness.update(currentUser);
Where my create method uses persist and the update method uses merge.
As I've said, they get inserted correctly into the database, but when I try to call:
List<Antrag> antraege = (List<Antrag>) user.getAntraege();
for(Antrag a : antraege){
News n = new News();
n.setDatum(a.getCreatedAt());
n.setStatus(a.isStatus());
n.setThema(a.getInfo());
List<User> beteiligte = a.getUsers();
System.out.println("Amount users " + beteiligte.size());
for (User z : beteiligte) {
System.out.println(z.getNachname() + " " + z.getId());
if(z.getId() != user.getId()){
n.setZustaendiger(z);
}
}
newsList.add(n);
}
-> Amount users returns 0 :(
So - in consequences: Antraege are added to Users, but users not to Antraege?
Edit: As it seems, my insertion of a new ManyToMany record is not correct.
Can anyone explain me the correct way ?

Related

How to copy an existing organisation role in Liferay and add it to Users that already had the original role?

So i am working with Liferay 7/Oracle 11g and i try to copy existing organization roles of a specified subtype, rename them and then add those new roles to users that had the original Roles.
So getting roles by subtype works pretty straightforward,
the first Problem arises after i add the new role, i receive an error message when trying to view the new Role:
Someone may be trying to circumvent the permission checker: {companyId=20115, name=com.liferay.portal.kernel.model.Role, primKey=31701, scope=4}
the second Problem is getting the Users that have the original Organization Role as i can't find an existing Liferay class that delivers me that Information. From what i know its saved withing the USERGROUPROLE table, so i could read it from there with my own SQL select, but i would prefer if there was a Liferay class that provided that information.
List<Role> lRole = RoleLocalServiceUtil.getSubtypeRoles(String.valueOf(adoptFromYear));
for(Role role : lRole) {
long roleId = CounterLocalServiceUtil.increment();
Role newRole = RoleLocalServiceUtil.createRole(roleId);
newRole.setClassPK(roleId);
newRole.setCompanyId(role.getCompanyId());
newRole.setUserId(role.getUserId());
newRole.setUserName(role.getUserName());
newRole.setClassName(role.getClassName());
newRole.setTitle(role.getTitle());
newRole.setDescription(role.getDescription());
newRole.setCreateDate(new Date());
newRole.setType(role.getType());
newRole.setName(replaceOrAppendYear(role.getName(), newYear));
newRole.setSubtype(String.valueOf(newYear));
RoleLocalServiceUtil.addRole(newRole);
//assign Users that have base Role, the new Role
long[] aUserId = UserLocalServiceUtil.getRoleUserIds(role.getRoleId());
for(long userId : aUserId) {
RoleLocalServiceUtil.addUserRole(userId, newRole.getRoleId());
}
}
UPDATE:
I fixed the first problem by using another addRole method of UserLocalServiceUtil, code is now as following:
List<Role> lRole = RoleLocalServiceUtil.getSubtypeRoles(String.valueOf(adoptFromYear));
for(Role role : lRole) {
Role newRole = RoleLocalServiceUtil.addRole(role.getUserId(), Role.class.getName(),
CounterLocalServiceUtil.increment(), replaceOrAppendYear(role.getName(), newYear),
role.getTitleMap(), role.getDescriptionMap(), role.getType(),
String.valueOf(newYear), null);
//add User from base Role to new Role
long[] aUserId = UserLocalServiceUtil.getRoleUserIds(role.getRoleId());
//aUserId still empty
for(long userId : aUserId) {
RoleLocalServiceUtil.addUserRole(userId, newRole.getRoleId());
}
}
So the Problem of getting all User that have a certain Organization Role still exists.
So my solution to my problems is as following, i used the other addRole method to add a new Role and that also creates the additional entry in the db so there is no error message anymore.
On my second problem, i just use the liferay API to get all entries from UserGroupRole Table and then i filter all the entries via the roleId that i need. Not a nice solution, but in my case even with tens of thousands of entries (and thats generous for what i work on) the function will be called once a year so ¯\_(ツ)_/¯
So here is the solution:
List<Role> lRole = RoleLocalServiceUtil.getSubtypeRoles(String.valueOf(adoptFromYear));
for(Role role : lRole) {
Role newRole = RoleLocalServiceUtil.addRole(role.getUserId(), Role.class.getName(),
CounterLocalServiceUtil.increment(), replaceOrAppendYear(role.getName(), newYear),
role.getTitleMap(), role.getDescriptionMap(), role.getType(), String.valueOf(newYear), null);
//get all User - Group (Organization) - Role Objects and filter by Role
List<UserGroupRole> lUserGroupRole = UserGroupRoleLocalServiceUtil
.getUserGroupRoles(QueryUtil.ALL_POS, QueryUtil.ALL_POS).stream()
.filter(ugr -> ugr.getRoleId() == role.getRoleId()).collect(Collectors.toList());
//add new Role to all existing Users that had the adopted role
long[] roleIds = {newRole.getRoleId()};
for(UserGroupRole ugr : lUserGroupRole) {
UserGroupRoleLocalServiceUtil.addUserGroupRoles(ugr.getUserId(), ugr.getGroupId(), roleIds);
}
}

Call transactional method Play Java JPA Hibernate

I have 2 database one is mysql and other is postgree.
I tried to get postgree data from mysql transactional method.
#Transactional(value = "pg")
public List<String> getSubordinate(){
Query q1 = JPA.em().createNativeQuery("select vrs.subordinate_number, vrs.superior_number\n" +
"from view_reporting_structure vrs\n" +
"where vrs.superior_number = :personel_number");
q1.setParameter("personel_number","524261");
List<String> me = q1.getResultList();
return me;
}
}
from another method
#Transactional
public Result getOpenRequestList(){
Subordinate subordinate = new Subordinate();
List<String> subordinateData = subordinate.getSubordinate();
....
}
i got error
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'db_hcm.view_reporting_structure' doesn't exist
so my Postgre method recognized as mySQL transaction which is the view not exist in mySQL database. how do I get data from different presistence unit with 1 method?
I never did it (different databases), but I guess the following may work.
For example, you have the following data source definition in application.conf:
# MySql
db.mysql.driver=com.mysql.jdbc.Driver
... the rest of setting for db.mysql
# H2
db.postgre.driver=org.postgresql.Driver
... the rest of setting for db.postgre
Instead of using #Transactional annotation, manage a transaction explicitly and use JPA withTransaction API:
private static final String MYSQL_DB = "mysql";
private static final String POSTGRE_DB = "postgre";
public List<String> getSubordinate() {
JPA.withTransaction(MYSQL_DB, true/* this is read-only flag*/,
() -> {
Query q1 = JPA.em().createNativeQuery("select vrs.subordinate_number, vrs.superior_number\n" +
"from view_reporting_structure vrs\n" +
"where vrs.superior_number = :personel_number");
q1.setParameter("personel_number","524261");
List<String> me = q1.getResultList();
return me;
}
}
public Result getOpenRequestList(){
JPA.withTransaction(POSTGRE_DB, true/* this is read-only flag*/,
() -> {
Subordinate subordinate = new Subordinate();
List<String> subordinateData = subordinate.getSubordinate();
....
}
}
Note: I prefer always use withTransaction, since it allows better control of unhappy flow. You should wrap the call with try-catch. If JPA throws a run-time exception on commit, you can do proper error handling. In case of using #Transactional annotation, commit takes place after controller have finished and you cannot handle the error.

Hibernate restrictions

I have a class named as Films and it has id, filmName, actionStatus and so on. I want to take the filmNames where its actionStatus=4. There are many filmNames with actionStatus=4.
I tried to do it this way:
Session ses = model.DBManager.getInstance().getSession();
List<Films> film_list;
Criteria criFilm = ses.createCriteria(Films.class);
criFilm.add(Restrictions.eq("actionStatus", 4));
film_list = criFilm.list();
for (Films films : film_list) {
System.out.println("film details " + films.getFilmName());
}
I'm not getting the required outputs by the above code.
Please help.

Java EE - JSF - Entity class #ManyToOne

First of all sorry for my dump english but i would ask a little help..
I have two oracle Db tables (events,documents) and i made two entity classes.
one:
public class BDocuments implements Serializable {
#JoinColumn(name = "B_EVENT_ID", referencedColumnName = "ID")
#ManyToOne
private BEvents bEventId;
...
...
two:
public class BEvents implements Serializable {
#Id
#Basic(optional = false)
#GeneratedValue(generator="EventSeq")
#SequenceGenerator(name="EventSeq",sequenceName="B_EVENTS_SEQ", allocationSize=1)
#Column(name = "ID")
private Integer id;
...
...
the id field of event table is the foreign key for the documents table event_id field..
Whene the user create a new event on the view the program create a new instance to the events table and if the events has an attached document then i’ll create a instance to the documents table. And of course the new event instance’s id will be the new document instance’s event_id..
it workd fine.. there is no probleme if i check the tables with TOAD i can see the 2 new instance..
After this i’ll see the new event ont he view and if I’ll click on this int he new dialog window i should see the events details.. like does this event has any attached documents..
JSF:
<p:column>
<f:facet name="header">
<h:outputText value="Esemény ID"/>
</f:facet>
<h:commandLink value="#{item.id}" >
<p:ajax listener="#{mainWorkingBean.showChosedEventDetails('dlgshowevent',item.id)}" />
</h:commandLink>
</p:column>
<p:column>
There is a managed beans that has a metod showChosedEventDetails() and after some validation check it invoke the DAO EJB’s following method, and then create a data table for the view by the returned List.
This is EJB method:
public List<BDocuments> showAllDocumentsOnEvents(Integer chosedEventid) {
if (chosedEventid != null) {
try {
System.out.println("showAllDocumentsOnEvents: event id:" + chosedEventid);
assert emf != null;
EntityManager em = null;
em = emf.createEntityManager();
List<BDocuments> documentList = new ArrayList();
BEvents documentDetailsInstance = (BEvents) em.createNamedQuery("BEvents.findById").setParameter("id", chosedEventid).getSingleResult();
//get the event instance by the id that received in the method paramter…
System.out.println("showAllDocumentsOnEvents NEW CHOSED INSTANCE: " + documentDetailsInstance);
Collection<BDocuments> allDocumentsCollection = documentDetailsInstance.getBDocumentsCollection(); //a #ManytoOne..
System.out.println("showAllDocumentsOnEvents EVENTINSTANCE: " + documentDetailsInstance.getEventText());
System.out.println("showAllDocumentsOnEvents COLLECTION: " + allDocumentsCollection.toString());
System.out.println("showAllDocumentsOnEvents NEW COLLECTION SIZE..: " + allDocumentsCollection.size() + "collection: " + allDocumentsCollection.toString()); // lame debugging.. checking the values..
int x;
for (x = 0; x < allDocumentsCollection.size();) {
System.out.println("Show all: for ciklus: Iterables kiszedve: " + Iterables.get(allDocumentsCollection, x));
BDocuments document = Iterables.get(allDocumentsCollection, x);
documentList.add(document);
x++;
} //check the collection and put the elements to the list.. .
return documentList;
} catch (NullPointerException e) {
System.out.println(e.getMessage());
return null;
}
} else {
System.out.println(" showAllDocumentsOnEvents ELSE ÁG...showAllDocumentsOnEvents: event id:" + chosedEventid);
return null;
}
}
It is ALSO work fine BUT the Collection allDocumentsCollection is empty!
I couldn’t be empty because i can see in the database there is in everything what should be in.
And now comming the real big question.. after i make clean and build and redeploy in netbeans and then click ont he same event on the view the Collection allDocumentsCollection WILL NOT BE empty…
I’m really don’t know why is this Collection empty before the redeploy.. and why not after the redeploy..
I would be really thankfull if somebody could help me..
thank you!
Odd that you showed everything but the getBDocumentsCollection mapping that is causing you problems, or the code used to set the relationships. But since you are saying the database is populated correctly and this is a bidirectional relationship, it is a fairly common mistake to only populate one side of the relationship. When you set the BDocuments.bEventId with a BEvents instance, you must also add that BDocuments instance to the BEvents.BDocumentsCollection to keep the relationship in synch with the database. JPA does not maintain relationships for you, so you either set both sides, or constantly refresh the object from the database when the transaction commits using em.refresh or provider specific api. Since refreshing has additional overhead, it is much better to just always keep both sides in sync.

Hibernate not deleting/updating one to many

I am trying to learn how to work with hibernate, and until now i thought i was doing ok...
The problem is, i have a one to many relationship that i can't update/delete.
My DB is pretty basic, i have a ClientsBasic that has a one to many relationship with IndirectClients (which simply has a ClientsBasic ID and a URL, both keys because you can have for the same ID lots of URLs)
ClientBasic:
#OneToMany(fetch = FetchType.EAGER, mappedBy = "clientsBasic", cascade=CascadeType.ALL)
public List<IndirectClients> getIndirectClients() {
return this.indirectClients;
}
public void setIndirectClients(List<IndirectClients> indirectClients) {
// this.indirectClients = indirectClients;
this.indirectClients.clear();
this.indirectClients.addAll(indirectClients);
}
ClientDao:
public ClientsBasic save(ClientsBasic client) throws HibernateException {
Transaction tx = null;
tx = session.beginTransaction();
session.saveOrUpdate(client);
tx.commit();
log.info("Client saved with id: " + client.getClientId());
return client;
}
Now if i try to delete ClientsBasic, it will delete both ClientsBasic and all related indirectClients, so its working as expected, but if i simply try to update/delete and entry in indirectClients it doesn't work.
Example:
I create a new Client
ClientsBasic cb = new ClientsBasic("company_1", 1234, "company_1#email.com");
cbDao.save(cb);
And then a new Indirect Client
List<IndirectClients> indirectClientsSet= new ArrayList<IndirectClients>();
indirectClientsSet.add(new IndirectClients(new IndirectClientsId(cb.getClientId(), "www.url.test_1.com"), cb));
cb.setIndirectClients(indirectClientsSet);
cbDao.save(cb);
Now if i try to change the url like this
ClientsBasic cb = cbDao.findClientById(1);
List<IndirectClients> indC = cb.getIndirectClients();
indC.get(0).getId().setUrl("TEST");
cb.setIndirectClients(indC);
cbDao.save(cb);
no changes are made in the DB.
Can someone please help me?
Thank you.
If your IndirectClients is defined as an Entity it has its own life cycle, meaning you have to persist/delete instances separately from their ClientBasic parent.
If you want a scenario where all children are managed through their parent relation, consider using ElementCollection.
See also JPA: When to choose Multivalued Association vs. Element Collection Mapping

Categories

Resources