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

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.

Related

getting Duplicate List Values in GET API service in spring Boot

i am getiing proper values from DB but Getting Duplicate List Values while add list object to class object, in Spring Boot
Please suggest to me how to do it.
Get data from DB Code : Here Rooms is my DB Entity class
CriteriaBuilder roomsBuilder = roomSession.getCriteriaBuilder();
CriteriaQuery<Rooms> query = roomsBuilder.createQuery(Rooms.class);
Root<Rooms> root = query.from(Rooms.class);
Predicate userRestriction = roomsBuilder.or(roomsBuilder.notEqual(root.get(SmatrEntityParameters.IS_DELETED), "Y"),
roomsBuilder.isNull(root.get(SmatrEntityParameters.IS_DELETED)));
Predicate userRestriction2 = roomsBuilder.and(roomsBuilder.equal(root.join("properties").get(SmatrEntityParameters.PROPERTY_ID), propertyId));
query.where(roomsBuilder.and(userRestriction, userRestriction2));
Query q = roomSession.createQuery(query);
List<Rooms> getroomslistobj= q.getResultList();
Iterate the list code: Here getAllRoomsobj means main response pojo class
List<GetAllRooms> getallroomslistobj = new ArrayList<GetAllRooms>();
for (int i = 0; i < getroomslistobj.size(); i++) {
int dbroomId = getroomslistobj.get(i).getRoomId();
String dbroomName = getroomslistobj.get(i).getRoomName();
// Actual code start
getAllRoomsobj.setRoomId(dbroomId);
getAllRoomsobj.setRoomName(dbroomName);
getallroomslistobj.add(getAllRoomsobj);
// Actual code end
}
I tried one code at the middle of the Actual code but I did not want create a new object for the response class:
GetAllRooms object = new GetAllRooms();
object.setRoomId(dbroomId);
object.setRoomName(dbroomName);
getallroomslistobj.add(object);
Please Help me Out,
Thanks in Advance
u can try it by stream.map() of java8

Hibernate update multiple Objects List

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

MongoTemplate upsert - easy way to make Update from pojo (which user has editted)?

Here is a simple pojo:
public class Description {
private String code;
private String name;
private String norwegian;
private String english;
}
And please see the following code to apply an upsert to MongoDb via spring MongoTemplate:
Query query = new Query(Criteria.where("code").is(description.getCode()));
Update update = new Update().set("name", description.getName()).set("norwegian", description.getNorwegian()).set("english", description.getEnglish());
mongoTemplate.upsert(query, update, "descriptions");
The line to generate the Update object specifies every field of the Item class manually.
But if my Item object changes then my Dao layer breaks.
So is there a way to avoid doing this, so that all fields from my Item class are applied automatically to the update?
E.g.
Update update = new Update().fromObject(item);
Note that my pojo does not extend DBObject.
I found a pretty good solution for this question
//make a new description here
Description d = new Description();
d.setCode("no");
d.setName("norwegian");
d.setNorwegian("norwegian");
d.setEnglish("english");
//build query
Query query = new Query(Criteria.where("code").is(description.getCode()));
//build update
DBObject dbDoc = new BasicDBObject();
mongoTemplate.getConverter().write(d, dbDoc); //it is the one spring use for convertions.
Update update = Update.fromDBObject(dbDoc);
//run it!
mongoTemplate.upsert(query, update, "descriptions");
Plz note that Update.fromDBObject return an update object with all fields in dbDoc. If you just want to update non-null fields, you should code a new method to exclude null fields.
For example, the front-end post a doc like below:
//make a new description here
Description d = new Description();
d.setCode("no");
d.setEnglish("norwegian");
We only need to update the field 'language':
//return Update object
public static Update fromDBObjectExcludeNullFields(DBObject object) {
Update update = new Update();
for (String key : object.keySet()) {
Object value = object.get(key);
if(value!=null){
update.set(key, value);
}
}
return update;
}
//build udpate
Update update = fromDBObjectExcludeNullFields(dbDoc);
The solution for a new spring-data-mongodb version 2.X.X.
The API has evolved, since 2.X.X version there is:
Update.fromDocument(org.bson.Document object, String... exclude)
instead of (1.X.X):
Update.fromDBObject(com.mongodb.DBObject object, String... exclude)
The full solution:
//make a new description here
Description d = new Description();
d.setCode("no");
d.setName("norwegian");
d.setNorwegian("norwegian");
d.setEnglish("english");
Query query = new Query(Criteria.where("code").is(description.getCode()));
Document doc = new Document(); // org.bson.Document
mongoTemplate.getConverter().write(item, doc);
Update update = Update.fromDocument(doc);
mongoTemplate.upsert(query, update, "descriptions");
It works!
you can use save : (if non exist = insert else = upsert)
save(Object objectToSave, String collectionName)
read : javadoc
Just like previous answers said, use mongoTemplate.getConverter().write() and Update.fromDocument() functions. But i found Update.fromDocument() won't add "$set" key and won't work directly, the solution is to add "$set" yourself, like below (PS: I'm using 2.2.1.RELEASE version):
public static Update updateFromObject(Object object, MongoTemplate mongoTemplate) {
Document doc = new Document();
mongoTemplate.getConverter().write(object, doc);
return Update.fromDocument(new Document("$set", doc));
}
If you want to upsert Pojos incl. property String id; you have to exclude the _id field in the fromDBObject method Update.fromDBObject(dbDoc,"_id").
Otherwise you get the Exception:
org.springframework.dao.DuplicateKeyException: { "serverUsed" : "127.0.0.1:27017" , "ok" : 1 , "n" : 0 , "updatedExisting" : false , "err" : "E11000 duplicate key error collection: db.description index: _id_ dup key: { : null }" , "code" : 11000}; nested exception is com.mongodb.MongoException$DuplicateKey: { "serverUsed" : "127.0.0.1:27017" , "ok" : 1 , "n" : 0 , "updatedExisting" : false , "err" : "E11000 duplicate key error collection: db.description index: _id_ dup key: { : null }" , "code" : 11000}
because the _id field of the first is null
{
"_id" : null,
...
}
Fullcode based on #PaniniGelato answer would be
public class Description(){
public String id;
...
}
Description d = new Description();
d.setCode("no");
d.setName("norwegian");
d.setNorwegian("norwegian");
d.setEnglish("english");
//build query
Query query = new Query(Criteria.where("code").is(description.getCode()));
//build update
DBObject dbDoc = new BasicDBObject();
mongoTemplate.getConverter().write(d, dbDoc); //it is the one spring use for convertions.
Update update = Update.fromDBObject(dbDoc, "_id");
//run it!
mongoTemplate.upsert(query, update, "descriptions");
Then the upsert is working in the cases of insert and update. Corrections & thoughts are welcome ;)
This is what I am doing for the time being. Not so much elegant way to do it, but it does save a precious DB call:
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Query;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBObject;
import com.mongodb.util.JSON;
/**
* Perform an upsert operation to update ALL FIELDS in an object using native mongo driver's methods
* since mongoTemplate's upsert method doesn't allow it
* #param upsertQuery
* #param object
* #param collectionName
*/
private void performUpsert(Query upsertQuery, Object object, String collectionName){
ObjectMapper mapper = new ObjectMapper();
try {
String jsonStr = mapper.writeValueAsString(object);
DB db = mongoTemplate.getDb();
DBCollection collection = db.getCollection(collectionName);
DBObject query = upsertQuery.getQueryObject();
DBObject update = new BasicDBObject("$set", JSON.parse(jsonStr));
collection.update(query, update, true, false);
} catch (IOException e) {
LOGGER.error("Unable to persist the metrics in DB. Error while parsing object: {}", e);
}
}
There are two cases here that need to be distinguished:
Update an item that was previously fetched from the DB.
Update or insert (upsert) an item you created by code.
In Case 1) You can simply use mongoTemplate.save(pojo, "collection"), because your POJO will already have a filled ObjectID in its id field.
In case 2) You have to explain to mongo what "already exists" means in case of your domain model: By default the mongoTemplate.save() method updates an existing item, if there is one with that same ObjectId. But with a newly instantiated POJO you do not have that id. Therefore the mongoTemplate.upsert() method has a query parameter that you can create like this:
MyDomainClass pojo = new MyDomainClass(...);
Query query = Query.query(Criteria.where("email").is("user1#domain.com"));
DBObject dbDoc = new BasicDBObject();
mongoTemplate.getConverter().write(pojo, dbDoc); //it is the one spring use for convertions.
dbDoc.removeField("_id"); // just to be sure to not create any duplicates
Update update = Update.fromDBObject(dbDoc);
WriteResult writeResult = mongoTemplate.upsert(query, update, UserModel.class);
I ran into the same problem. In het current Spring Data MongoDB version no such thing is available. You have to update the seperate fields by hand.
However it is possible with another framework: Morphia.
This framework has a wrapper for DAO functionality: https://github.com/mongodb/morphia/wiki/DAOSupport
You can use the DAO API to do things like this:
SomePojo pojo = daoInstance.findOne("some-field", "some-value");
pojo.setAProperty("changing this property");
daoInstance.save(pojo);
I think that:
Description add a property
#Id
private String id;
then get a document by the query condition,set Description's id by document's id.
and save
Just use ReflectionDBObject - if you make Description extend it, you should just get your object's fields transferred to Update reflectively, automagically. The note from above about null fields included in the update still holds true.
public void saveOrUpdate(String json) {
try {
JSONObject jsonObject = new JSONObject(json);
DBObject update1 = new BasicDBObject("$set", JSON.parse(json));
mongoTemplate.getCollection("collectionName").update(new Query(Criteria.where("name").is(jsonObject.getString("name"))).getQueryObject(), update1, true, false);
} catch (Exception e) {
throw new GenericServiceException("Error while save/udpate. Error msg: " + e.getMessage(), e);
}
}
this is very simple way to save json string into collection using mongodb
and spring.
This method can be override to use as JSONObject.
#Override
public void updateInfo(UpdateObject algorithm) {
Document document = new Document();
mongoTemplate.getConverter().write(algorithm, document);
Update update = Update.fromDocument(document);
mongoTemplate.updateFirst(query(where("_id").is(algorithm.get_id())), update, UpdateObject.class);
}
After upsert, I was Tring to fetch same record but it was given me the old one.
But in dB I am having new records.

Google App Engine Ancestor Query

I am apparently confused as to how the GAE ancestor query should work. My understanding was that an ancestor query should return all descendent generations, not just immediate children. Yet if I modify the example from the Developer Guide as follows, I retrieve only the immediate children, never the grandchild. What am I missing?
Entity person = new Entity("Person", "tom");
Entity weddingPhoto = new Entity("Photo", person.getKey());
weddingPhoto.setProperty("imageUrl",
"http://domain.com/some/path/to/wedding_photo.jpg");
Entity babyPhoto = new Entity("Photo", person.getKey());
babyPhoto.setProperty("imageUrl",
"http://domain.com/some/path/to/baby_photo.jpg");
// add this grandchild:
Entity grandbabyPhoto = new Entity("Photo", babyPhoto.getKey());
grandbabyPhoto.setProperty("imageUrl",
"http://domain.com/some/path/to/grandbabyPhoto.jpg");
Entity dancePhoto = new Entity("Photo", person.getKey());
dancePhoto.setProperty("imageUrl",
"http://domain.com/some/path/to/dance_photo.jpg");
Entity campingPhoto = new Entity("Photo");
campingPhoto.setProperty("imageUrl",
"http://domain.com/some/path/to/camping_photo.jpg");
getDatastore().put(
java.util.Arrays.asList(person, weddingPhoto, babyPhoto, dancePhoto, campingPhoto));
Query userPhotosQuery = new Query("Photo");
userPhotosQuery.setAncestor(person.getKey());
// This returns weddingPhoto, babyPhoto and dancePhoto, but
// not grandbabyPhoto --- why???
List<Entity> results =
getDatastore().prepare(userPhotosQuery).asList(
FetchOptions.Builder.withDefaults());
Thanks very much for any help you can provide!
Because your put(..) statement does not contain grandbabyPhoto, so it does not get saved.

JPA RollbackException but not in unit test

I have a java project with a collection of unit tests that perform simple updates, deletes using JPA2. The unit tests run without a problem, and I can verify the changes in the database - all good. I attempt to copy/paste this same function in a handler (Smartfox Extension) - I recieve a rollback exception.
Column 'levelid' cannot be null.
Looking for suggestions as to why this might be. I can perform data reads from within this extension ( GetModelHandler ) but trying to set data does not work. It's completely baffling.
So in summary -
This works...
#Test
public void Save()
{
LevelDAO dao = new LevelDAO();
List levels = dao.findAll();
int i = levels.size();
Level l = new Level();
l.setName("test");
Layer y = new Layer();
y.setLayername("layer2");
EntityManagerHelper.beginTransaction();
dao.save(l);
EntityManagerHelper.commit();
}
This fails with rollback exception
public class SetModelHandler extends BaseClientRequestHandler
{
#Override
public void handleClientRequest(User sender, ISFSObject params)
{
LevelDAO dao = new LevelDAO();
List levels = dao.findAll();
int i = levels.size();
Level l = new Level();
l.setName("test");
Layer y = new Layer();
y.setLayername("layer2");
EntityManagerHelper.beginTransaction();
dao.save(l);
EntityManagerHelper.commit();
}
}
The Level and Layer class have a OneToMany and ManyToOne attribute respectively.
Any ideas appeciated.
Update
Here's the schema
Level
--------
levelid (int) PK
name (varchar)
Layer
--------
layerid (int) 11 PK
layername (varchar) 100
levelid (int)
Foreign Key Name:Level.levelid ,
On Delete: no action,
On Update: no action
When I changed
EntityManagerHelper.beginTransaction();
dao.update(l);
EntityManagerHelper.commit();
to
EntityManagerFactory factory = Persistence.createEntityManagerFactory("bwmodel");
EntityManager entityManager = factory.createEntityManager();
entityManager.getTransaction().begin();
dao.update(l);
entityManager.persist(l);
entityManager.getTransaction().commit();
This performs a save but not an update ? I'm missing something obvious here.
The most likely problem I can see would be different database definitions. Testing EJBs often use an in-memory database that is generated on the fly. Whereas in actual production you are using a real database which is probably enforcing constraints.
Try assigning the levelid value a value or changing the database schema.

Categories