Hibernate update multiple Objects List - java

I have different types of objects to update. All objects are set to a list and pass them to a method.
List list = new ArrayList();
list.add(mediaInfo); // Class MediaInfo
list.add(mediaMode); // Class MediaMode
list.add(paidCustomer); // Class paidCustomer
updateList ( l );
All above objects have loaded before and I have changed one field (called "position" : String value). Also above any object is not attached to any hb session. Those objects are loaded in another place. I just want to update them with updated data.
public boolean updateList(java.util.List <Object> dataList){
Session session = null;
Hbutility myHbutil = null;
try {
myHbutil = new Hbutility();
session = myHbutil.getSession();
Transaction tx = session.beginTransaction();
for(Object entity: dataList){
logger.info("Updating Objects : " + entity );
session.update( entity );
}
tx.commit();
} catch (Exception e) {
e.printStackTrace();
}finally{
session.close();
}
return updateStaus;
}
All objects have their id s. But they are not updated. Any one See any problem here ?
There are many samples of hibernate update in google. But all of them shows, loading a object inside the session, setting new values and simply updating. In my scenario, objects are loaded out of the session and all of them are different type of objects. Any help please.

To update the content, you can also use the merge method. Maibe it can help you ?
Try to get objet with the entities manager. Then modify the properties. And save change Exemple :
MediaInfo tmp = em.find(MediaInfo.class, mediaInfo.getId();
//Modify some properties
tmp.setMachin(....);
list.add(tmp);
updateList ( list );

Need to ensure that your mapping for 'position' is as per your expectation, ie it should'nt be transient and updatable should'nt be false

Related

How to access a specific list of fields from a model object

I have the below Stream class that is getting returned from DB:
Stream<Transaction> transctions=transRepository.findByTransctionId();
public class Transaction{
String transctionId;
String accountId;
String transName;
String accountName;
}
Now my Requirement is as below:
Transaction entity has 4 fields. So, from DB all the 4 fields were fetched by Jpa.
But client who needs this data ,he has sent the columnsName in list that he is looking from Transaction model
List<String> columnNames=Arrays.asList("transctionId","accountName")
I have post this data to Kafka.I have to take each Transction from this stream post it to kafka.
But cline is looking for only this 2 fields "transctionId","accountName" should go as part of Transaction in Kafka instead of all 4 fields.
The data should go in form of json to Kafa having below format:
{
"transctionId":"1234",
"accountName" :"test-account"
}
Basically only those fields should go to kafka which they have asked for instead of converting the whole pojo to json and send it.
Is there any way to achieve that?
If you need to invoke a method, but you only have its name, the only way I know is via reflection. I would do it like this:
Stream<Transaction> transctions=transRepository.findByTransctionId();
List<Transaction> outTransactions = new ArrayList<>();
List<String> columnNames = new ArrayList<>();
transactions.forEach(tr -> {
Transaction outTransaction = new Transaction();
columnNames.forEach( col -> {
try {
var getMethod = tr.getClass().getMethod("get" + StringUtils.capitalize(col));
Object value = getMethod.invoke(tr);
String valueStr = value instanceof String ? value.toString() : "";
var setMethod = outTransaction.getClass().getMethod("set" + StringUtils.capitalize(col));
setMethod.invoke(outTransaction, valueStr);
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
e.printStackTrace();
}
});
outTransactions.add(outTransaction);
});
There is a lot of traversing, but with the requirements you have, this is the generic solution I can come up with. Another shortcoming to this solution is the creation of new Transaction objects. Which means that if Transactions are many, memory usage can grow. Maybe this solution can be optimised to take advantage of streaming the transactions from the DB.
Another way to do it is to have different endpoints for each known set of properties that the client sends you. For example:
#GetMapping("/transaction_id_and_name")
List<Transaction> getTransactionsIdAndName() {
... obtain Transactions, return a new list of Transactions, with transaction_id and name ... }
#GetMapping("/transaction_id_and_status")
List<Transaction> getTransactionsNameAndStatus() {...}

aem 6.1 extend user properties

Printscreen additional fields useradmin
How can I add some new User Properties to the CQ Users?
I found an solution but it don't work --> http://experience-aem.blogspot.ch/2014/01/aem-cq-56-extend-useradmin-add-new-user.html
I tried to manipulate in CRX the UserProperties.js with new Properties, I see them in useradmin but if I try to add the new propertie in Java Code (not via useradmin) I can save it without error, but the value is empty in useradmin.
And if I try to add some value via useradmin for the new propertie, all user gets the same value.
How can I add new User Properties, that I can set the Value via Java code like the standard properties.
user = userManager.createUser(username, password);
ValueFactory valueFactory = session.getValueFactory();
emailValue = valueFactory.createValue(email);
givennameValue = valueFactory.createValue(givenname);
nameValue = valueFactory.createValue(name);
//User class just accepts Value Object
user.setProperty("profile/" + UserProperties.EMAIL, emailValue);
user.setProperty("profile/" + UserProperties.FAMILY_NAME, nameValue);
user.setProperty("profile/" + UserProperties.GIVEN_NAME, givennameValue);
I found an solution.
Go to crx /libs/cq/security/widgets/source/widgets/security/UserProperties.js
add the fields you need in the items array of the user (Caution - there are items for user and items for groups in the same place)
in the loadRecord method of your JS, you have to add each new field to the "record" object
"items":[{
"xtype":"textfield",
"fieldLabel":CQ.I18n.getMessage("Mail"),
"anchor":"100%",
"vtype":"email",
"msgTarget":"under",
"name":"email"
},{
"xtype":"textfield",
"fieldLabel":CQ.I18n.getMessage("My Field"),
"anchor":"100%",
"msgTarget":"under",
"name":"myfield"
},{
"xtype":"textarea",
"fieldLabel":CQ.I18n.getMessage("About"),
"anchor":"100% -155",
"name":"aboutMe"
}],
loadRecord: function(rec) {
this.enableUserSaveButton(false);
this.enableGroupSaveButton(false);
var type = rec.get("type");
if (type=="user") {
this.activeForm = this.userForm;
this.hiddenForm = this.groupForm;
if (rec.id==CQ.security.UserProperties.ADMIN_ID) {
this.pwdButtons.each(function(bt) {bt.hide(); return true;} )
} else {
this.pwdButtons.each(function(bt) {bt.show(); return true;} )
}
} else {
this.activeForm = this.groupForm;
this.hiddenForm = this.userForm;
}
//is loading additional property from json and show it in formular
rec.data["myfield"] = rec.json["myfield"];
this.activeForm.getForm().loadRecord(rec);
In the java code you can then add the new properties via the "user" object to the new properties. Note that the properties are put into the subfolder "profile".
user.setProperty("profile/" + "myfield", myFieldValue);
Did you try the second approach, posted by "pedro" in the link you've posted?
It probably has to do with pushing the new field to the record:
http://experience-aem.blogspot.com/2014/01/aem-cq-56-extend-useradmin-add-new-user.html?showComment=1390804750445#c2823498719990547675
i hope this may helps you the file exist on http://[host name]:[port]/crx/de/index.jsp#/libs/cq/security/widgets/source/widgets/security/UserProperties.js
and you will have two major properties the first one is for the user this.userForm the other one is this.groupForm for groups.

Why System.out.println() can solving my Hibernate Session?

Hello I'm newbie in learning hibernate framework. I was solved my error but I don't know what the problem happen. In my project I have 2 tables Tblbarang and Tbljenis. And 1 field at Tblbarang had relations as foreign key by Tbljenis.
I want to update Tblbarang table. I had two method
private void getcombobarang() {
Query q = sess.createQuery("from Tblbarang");
arrbarang = new ArrayList<>();
DefaultComboBoxModel comboModel = new DefaultComboBoxModel();
for (Object o : q.list()) {
Tblbarang coba = (Tblbarang) o;
comboModel.addElement(coba.getNamabarang());
arrbarang.add(coba);
}
combobarang.setModel(comboModel);
}
This method to set model combobox which I would choose to set the table Tblbarang item.
and now this method to update my Table Tblbarang
sess = NewHibernateUtil.getSessionFactory().openSession();
sess.beginTransaction();
Tblbarang tb = new Tblbarang();
tb.setKodbarang(arrbarang.get(combobarang.getSelectedIndex()).getKodbarang());
tb.setNamabarang(arrbarang.get(combobarang.getSelectedIndex()).getNamabarang());
tb.setTbljenis(arrbarang.get(combobarang.getSelectedIndex()).getTbljenis());
tb.setHarganet(arrbarang.get(combobarang.getSelectedIndex()).getHarganet());
tb.setHargajual(arrbarang.get(combobarang.getSelectedIndex()).getHargajual());
System.out.println(arrbarang.get(combobarang.getSelectedIndex()).getTbljenis()); // <-- this line resolved my problem
int st = Integer.parseInt(stok.getText()) ;
int jm = Integer.parseInt(jumlah.getText());
String totss = String.valueOf(st + jm);
Short totstok = Short.parseShort(totss);
tb.setStok(totstok);
sess.update(tb);
sess.getTransaction().commit();
when without System.out.print() the error are following
org.hibernate.HibernateException: illegally attempted to associate a proxy with two open Sessions
at org.hibernate.proxy.AbstractLazyInitializer.setSession(AbstractLazyInitializer.java:126)
at org.hibernate.proxy.AbstractLazyInitializer.setSession(AbstractLazyInitializer.java:126)
at org.hibernate.engine.StatefulPersistenceContext.reassociateProxy(StatefulPersistenceContext.java:573)
at org.hibernate.engine.StatefulPersistenceContext.reassociateIfUninitializedProxy(StatefulPersistenceContext.java:533)
at org.hibernate.event.def.ProxyVisitor.processEntity(ProxyVisitor.java:50)
at org.hibernate.event.def.AbstractVisitor.processValue(AbstractVisitor.java:125)
at org.hibernate.event.def.AbstractVisitor.processValue(AbstractVisitor.java:83)
at org.hibernate.event.def.AbstractVisitor.processEntityPropertyValues(AbstractVisitor.java:77)
at org.hibernate.event.def.AbstractVisitor.process(AbstractVisitor.java:144)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performUpdate(DefaultSaveOrUpdateEventListener.java:314)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsDetached(DefaultSaveOrUpdateEventListener.java:246)
at org.hibernate.event.def.DefaultUpdateEventListener.performSaveOrUpdate(DefaultUpdateEventListener.java:57)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:93)
at org.hibernate.impl.SessionImpl.fireUpdate(SessionImpl.java:742)
at org.hibernate.impl.SessionImpl.update(SessionImpl.java:730)
at org.hibernate.impl.SessionImpl.update(SessionImpl.java:722)
at retail.ui.frmBarangMasuk.tambahitemActionPerformed(frmBarangMasuk.java:622) //<-this line directing to sess.update(tb)
I will simply my code like this
sess = NewHibernateUtil.getSessionFactory().openSession();
sess.beginTransaction();
Tblbarang tb = (Tblbarang) arrbarang.get(combobarang.getSelectedIndex());
System.out.println(arrbarang.get(combobarang.getSelectedIndex()).getTbljenis());
int st = Integer.parseInt(stok.getText()) ;
int jm = Integer.parseInt(jumlah.getText());
String totss = String.valueOf(st + jm);
Short totstok = Short.parseShort(totss);
tb.setStok(totstok);
sess.update(tb);
sess.getTransaction().commit();
but the exception showing same error. I want to know what happen with my code? anyone can explain with that issue or this is bug from hibernate, thanks
In getcombobarang, you have a sess(session1) to get objects from database. And when updating tb, you open another sess(session2).
If Tblbarang contains a foreign-key object, in this case, which must associates with session1, because it's obtained from the function getcombobarang at first. So sess.update() throws an exception as you have seen.
For solution:
use merge() instead of update()
before update, copy the foreign-key object's properties to a whole new object, then set it into tb
I'm also confused about the impact of System.println() here.

Why does app engine bill me less when the below code is wrapped in a transaction?

I have verified this multiple times using appstats. When the below code is NOT wrapped in a transaction, JDO performs two datastore reads and one write, 3 RPC's, at a cost of 240. Not just the first time, every time, even though it is accessing the same record every time hence should be pulling it from cache. However, when I wrap the code in a transaction as above, the code makes 4 RPC's: begin transaction, get, put, and commit -- of these, only the Get is billed as a datastore read, so the overall cost is 70.
If it's pulling it from cache, why would it only bill for a read? It would seem that it would bill for a write, not a read. Could app engine be billing me the same amount for non-transactional cache reads as it does for datastore reads? why?
This is the code WITH transaction:
PersistenceManager pm = PMF.getManager();
Transaction tx = pm.currentTransaction();
String responsetext = "";
try {
tx.begin();
Key userkey = obtainUserKeyFromCookie();
User u = pm.getObjectById(User.class, userkey);
Key mapkey = obtainMapKeyFromQueryString();
// this is NOT a java.util.Map, just FYI
Map currentmap = pm.getObjectById(Map.class, mapkey);
Text mapData = currentmap.getMapData(); // mapData is JSON stored in the entity
Text newMapData = parseModifyAndReturn(mapData); // transform the map
currentmap.setMapData(newMapData); // mutate the Map object
tx.commit();
responsetext = "OK";
} catch (JDOCanRetryException jdoe) {
// log jdoe
responsetext = "RETRY";
} catch (Exception e) {
// log e
responsetext = "ERROR";
} finally {
if (tx.isActive()) {
tx.rollback();
}
pm.close();
}
resp.getWriter().println(responsetext);
This is the code WITHOUT the transaction:
PersistenceManager pm = PMF.getManager();
String responsetext = "";
try {
Key userkey = obtainUserKeyFromCookie();
User u = pm.getObjectById(User.class, userkey);
Key mapkey = obtainMapKeyFromQueryString();
// this is NOT a java.util.Map, just FYI
Map currentmap = pm.getObjectById(Map.class, mapkey);
Text mapData = currentmap.getMapData(); // mapData is JSON stored in the entity
Text newMapData = parseModifyAndReturn(mapData); // transform the map
currentmap.setMapData(newMapData); // mutate the Map object
responsetext = "OK";
} catch (Exception e) {
// log e
responsetext = "ERROR";
} finally {
pm.close();
}
resp.getWriter().println(responsetext);
With the transaction, the PersistenceManager can know that the caches are valid throughout the processing of that code. Without the transaction, it cannot (it doesn't know whether some other action has come in behind its back and changed things) and so must validate the cache's contents against the DB tables. Each time it checks, it needs to create a transaction to do so; that's a feature of the DB interface itself, where any action that's not in a transaction (with a few DB-specific exceptions) will have a transaction automatically added.
In your case, you should have a transaction anyway, because you want to have a consistent view of the database while you do your processing. Without that, the mapData could be modified by another operation while you're in the middle of working on it and those modifications would be silently lost. That Would Be Bad. (Well, probably.) Transactions are the cure.
(You should also look into using AOP for managing the transaction wrapping; that's enormously easier than writing all that transaction management code yourself each time. OTOH, it can add a lot of complexity to deployment until you get things right, so I could understand not following this piece of adviceā€¦)

Saving huge lists of objects taking lot of time

I am trying to do some big lists of object saving using hibernate..
problem is before saving I need to confirm if a record with same field data already exists if yes then need to fetch its id and create an association in another table.. else make a new entry and a new insert in the association table for the same..
Please guide me how I can improve the save time..
following is how the save is done..
Session session = SchemaManager.getDatabaseSession("com.server.domin.PublicaccountBehavior");
try {
List<Post> posts = this.getAllPosts();
Transaction transaction = session.beginTransaction();
for (Post post : posts) {
Behavior behavior = new Behavior();
behavior.setElementValue(val);
behavior.setIsDeleted(false);
Date now = new Date();
behavior.setCreatedOn(now);
behavior.setModifiedOn(now);
PublicaccountType type = new PublicaccountType();
type.setId(3L);
behavior.setPublicaccountType(type);
PublicaccountBehavior publicaccountBehavior = new PublicaccountBehavior();
publicaccountBehavior.setBehavior(behavior);
publicaccountBehavior.setPublicAccount(account);
publicaccountBehavior.setTimeOfBookmark(post.getTimeAsDate());
publicaccountBehavior.setCreatedOn(now);
publicaccountBehavior.setModifiedOn(now);
try {
Behavior behav;
List list2 = session.createQuery("from Behavior where elementValue = :elementVal").setString("elementVal",
behavior.getElementValue()).list();
if (list2.size() > 0) {
behav = (Behavior) list2.get(0);
publicaccountBehavior.setBehavior(behav);
} else {
Long id = (Long) session.save(behavior);
behavior.setId(id);
publicaccountBehavior.setBehavior(behavior);
}
session.saveOrUpdate(publicaccountBehavior);
} catch (HibernateException e) {
e.printStackTrace();
}
}
transaction.commit();
When you are saving a new object - flush() and then clear() the session regularly in order to control the size of the first-level cache. which will enhance the performance.
example is explained in hibernate docs.

Categories