JPA RollbackException but not in unit test - java

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.

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() {...}

How can I get springboot transaction'data in jooq query

So I have a problem in jooq about getting data in spring-boot transaction.
I use a transaction to save the base data, and then I want to use jooq to get these data. But I found that what I fetched is null.
String sql = dslContext.select().from(Tables.SALES_INVENTORY).getSQL();
System.out.println(sql);
Result<Record> fetch1 = dslContext.select().from(Tables.SALES_INVENTORY).fetch();
System.out.println(fetch1);
String groupbySql =
dslContext
.select(Tables.SALES_INVENTORY.ITEM_ID, sum(Tables.SALES_INVENTORY.ON_HAND_QTY))
.from(Tables.SALES_INVENTORY)
.groupBy(Tables.SALES_INVENTORY.ITEM_ID)
.getSQL();
System.out.println(groupbySql);
Result<Record2<UUID, BigDecimal>> fetch =
dslContext
.select(Tables.SALES_INVENTORY.ITEM_ID, sum(Tables.SALES_INVENTORY.ON_HAND_QTY))
.from(Tables.SALES_INVENTORY)
.groupBy(Tables.SALES_INVENTORY.ITEM_ID)
.fetch();
System.out.println(fetch);
List<SalesInventoryEntity> all = salesInventoryRepository.findAll();
all.forEach(s -> System.out.println(s));
Jooq's SQL is correct, but can't find and data return as if I use JPA #Transactional to do my test method. And I use jpa-repository to get data, it found the right data.
So my main problem is how can I get the right data in JPA transactional?
Here is what I used to init the base data. It's a test method, and its class is #Transactional, so this means that the method is also #Transactional?
public void initSalesInventories() {
List<SalesInventoryEntity> salesInventories = Lists.newArrayList();
ItemEntity itemEntity = itemRepository.findById(itemId1).get();
int i = 0;
for (StockLocationEntity stockLocationEntity : stockLocationEntities) {
SalesInventoryEntity salesInventoryEntity = new SalesInventoryEntity();
salesInventoryEntity.setStockLocation(stockLocationEntity);
salesInventoryEntity.setSalesOrganization(usSalesOrgEntity);
salesInventoryEntity.setItem(itemEntity);
salesInventoryEntity.setItemClass(ItemClass.SALEABLE);
salesInventoryEntity.setOnHandQty(100);
salesInventoryEntity.setReservedQty(0);
salesInventoryEntity.setAvailableQty(100);
salesInventoryEntity.setLeadTime(5);
DocumentType[] values = DocumentType.values();
salesInventoryEntity.setDocType(values[i % 7]);
String code = "TO-201906112010000" + i;
i++;
salesInventoryEntity.setDocCode(code);
salesInventories.add(salesInventoryEntity);
}
salesInventoryRepository.saveAll(salesInventories);
}
After init my base data, I used jooq to read the data, and find nothing. I don't know whether jooq can't read other transaction's data or jooq just read the actual data from the database. If you know something about it please give me some advices.

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.

Broadleaf - Create Dynamic Product Exception

I am new to Broadleaf and have been spending time with Broadleaf Demo project to familiarize with the framework.
I am using the current stable Broadleaf version - v2.2.
My aim is to create a dynamic category/product without using the Admin console. However, I am getting TransientObjectException:
java.lang.IllegalStateException: org.hibernate.TransientObjectException: object is an unsaved transient instance - save the transient instance before merging: org.broadleafcommerce.core.catalog.domain.CategoryImpl
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1386)
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1317)
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1323)
This is how I am trying to create category/product:
private void addProductMetaData(Product product) {
product.setName("phone A");
product.setFeaturedProduct(true);
product.setUrl("/phones/phoneA");
product.setCanSellWithoutOptions(true);
product.setManufacturer("manufacturer A");
product.setActiveStartDate(new Date());
product.setActiveEndDate(null);
addMediaInformation(product);
Category category = retrieveCategory();
product.setDefaultCategory(category);
// product.getAllParentCategories().add(category);
catalogService.saveProduct(product); //**Exception occurs here**
}
private Category retrieveCategory() {
List<Category> categories = catalogService.findCategoriesByName("phones");
Category category = (CollectionUtils.isEmpty(categories) ? catalogService.createCategory() : categories.get(0));
if (StringUtils.isEmpty(category.getName())) {
category.setName("phones");
category.setUrl("/phones");
Category parentCategory = catalogService.findCategoriesByName("Primary Nav").get(0);
category.setDefaultParentCategory(parentCategory);
category.setActiveStartDate(new Date());
category.getAllParentCategories().add(parentCategory);
catalogService.saveCategory(category);
}
return category;
}
Can someone explain why I am getting this exception( since category has been persisted) and how do I resolve it?
Looks to me like catagories list is empty, resulting in a call to service that fetches you new Category. Now, though you are associated this new category with product, but this new category is not saved in database.
You need to persist this new category first and than call save on product. This should resolve the issue.
And if this category is persisted than somehow hibernate is not able match this category with the one that you think is persisted.
I figured out the fix. Modified the line : catalogService.saveCategory(category);
to category = catalogService.saveCategory(category); and I am no longer getting the exception.

ormlite with persistent h2 db - new tables not get persisted

When I am creating a new H2 database via ORMLite the database file get created but after I close my application, all the data that it stored in the database is lost:
JdbcConnectionSource connection =
new JdbcConnectionSource("jdbc:h2:file:" + path.getAbsolutePath() + ".h2.db");
TableUtils.createTable(connection, SomeClass.class);
Dao<SomeClass, Integer> dao = DaoManager.createDao(connection, SomeClass.class);
SomeClass sc = new SomeClass(id, ...);
dao.create(sc);
SomeClass retrieved = dao.queryForId(id);
System.out.println("" + retrieved);
This code will produce good results. It will print the object that I stored.
But when I start the application again this time without creating the table and storing new object I get an exception telling me that the required table is not exists:
JdbcConnectionSource connection =
new JdbcConnectionSource("jdbc:h2:file:" + path.getAbsolutePath() + ".h2.db");
Dao<SomeClass, Integer> dao = DaoManager.createDao(connection, SomeClass.class);
SomeClass retrieved = dao.queryForId(id); // will produce an exception..
System.out.println("" + retrieved);
The following worked fine for me if I ran it once and then a second time with the createTable turned off. The 2nd insert gave me a primary key violation of course but that was expected. It created the file with (as #Thomas mentioned) a ".h2.db.h2.db" prefix.
Some questions:
After you run your application the first time, can you see the path file being created?
Is it on permanent storage and not in some temporary location cleared by the OS?
Any chance some other part of your application is clearing it before the database code begins?
Hope this helps.
#Test
public void testStuff() throws Exception {
File path = new File("/tmp/x");
JdbcConnectionSource connection = new JdbcConnectionSource("jdbc:h2:file:"
+ path.getAbsolutePath() + ".h2.db");
// TableUtils.createTable(connection, SomeClass.class);
Dao<SomeClass, Integer> dao = DaoManager.createDao(connection,
SomeClass.class);
int id = 131233;
SomeClass sc = new SomeClass(id, "fopewjfew");
dao.create(sc);
SomeClass retrieved = dao.queryForId(id);
System.out.println("" + retrieved);
connection.close();
}
I can see Russia from my house:
> ls -l /tmp/
...
-rw-r--r-- 1 graywatson wheel 14336 Aug 31 08:47 x.h2.db.h2.db
Did you close the database? It is closed automatically but it's better to close it manually (so recovery is faster).
In many cases the database URL is the problem. Are you sure the same path is used in both cases? Otherwise you end up with two databases. By the way, ".h2.db" is added automatically, you don't need to add it manually.
To better analyze the problem, you could append ;TRACE_LEVEL_FILE=2 to the database URL, and then check in the *.trace.db file what SQL statements were executed against the database.

Categories