I used JBOSS Hibernate tools to reverse engineer the MS SQL Server to get my data model objects.
I then wrote a small test program in Java to open a session, use the configuration, instantiate a Customer object, persist it into the database.
The sample runs writing one record to the database and closing the session.
What is weird, I have never seen this before is the 'oriental' characters being saved into the database columns.
Database:
SQL Server (Express) 10.50.1600 on Windows 2012 R2 Standard
Columns customerCode and customerName are nvarchar, null
Java App: Eclipse Neon, Maven, Hibernate 4.3, Java 1.8
NOTE: I am a newbie to Hibernate.
What else can I try or refactor?
Things I tried
Do a SQL Insert with IBM data studio (success)
No Success
Add the UTF-8 in connection url
Add the UTF-8 in hibernate xml
Create a SqlServerDialectWithNvarchar Class and enter it into hibernate xml.
public class SqlServerDialectWithNvarchar extends org.hibernate.dialect.SQLServerDialect{
public SqlServerDialectWithNvarchar(){
registerHibernateType(Types.NVARCHAR, 4000, "string");
registerColumnType(Types.BIGINT, "bigint");
registerColumnType(Types.BIT, "bit");
registerColumnType(Types.CHAR, "nchar(1)");
registerColumnType(Types.VARCHAR, 4000, "nvarchar($l)");
registerColumnType(Types.VARCHAR, "nvarchar(max)");
registerColumnType(Types.VARBINARY, 4000, "varbinary($1)");
registerColumnType(Types.VARBINARY, "varbinary(max)");
registerColumnType(Types.BLOB, "varbinary(max)");
registerColumnType(Types.CLOB, "nvarchar(max)");
}
}
Main Program:
public static void main(String[] args) {
String btnName = "OrderTrack.java ";
System.out.println(btnName + " started.");
System.out.println(btnName + " hibernate.enh-tas.cfg.xml");
Configuration cfg1 = new Configuration();
cfg1.configure("/hibernate.enh-tas.cfg.xml");
SessionFactory sf1 = cfg1.configure().buildSessionFactory();
System.out.println(btnName + " open hibernate session.");
Session session = sf1.openSession();
session.beginTransaction();
TblCustomers customer = new TblCustomers();
customer.setCustomerName("TEST XXX");
customer.setCustomerCode("DELETE ME");
session.persist(customer);
session.getTransaction().commit();
System.out.println(btnName + " closing hibernate session.");
session.close();
System.out.println(btnName + " session closed.");
}
SELECT Query using IBM Data Studio after main program runs
customerId customerCode customerName
---------- -------------- ---------------
30 Ԁt䐉䱅呅⁅䕍 Ԁt合卅⁔塘X
Hibernate XML
hibernate-configuration>
<session-factory>
<property name="hibernate.connection.useUnicode">true</property>
<property name="hibernate.connection.characterEncoding">utf-8</property>
<property name="hibernate.bytecode.use_reflection_optimizer">false</property>
<property name="hibernate.connection.driver_class">com.microsoft.sqlserver.jdbc.SQLServerDriver</property>
<property name="hibernate.connection.password">pwd</property>
<property name="hibernate.connection.url">jdbc:sqlserver://serverhost:1433;characterEncoding=UTF-8;</property>
<property name="hibernate.connection.username">tms</property>
<property name="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</property>
<property name="hibernate.encrypt">false</property>
<property name="hibernate.search.autoregister_listeners">true</property>
<property name="hibernate.show_sql">false</property>
<property name="hibernate.validator.apply_to_ddl">false</property>
Customer Class
/**
* TblCustomers generated by hbm2java
*/
#Entity
#Table(name = "tblCustomers", schema = "dbo", catalog = "TAS", uniqueConstraints = #UniqueConstraint(columnNames = {
"customerCode", "customerContact" }))
public class TblCustomers implements java.io.Serializable {
private Integer customerId;
private TblFrequency tblFrequency;
private Boolean customerLocked;
private Boolean customerDeleted;
private Serializable customerCode;
private Serializable customerName;
private Boolean customerIsOperator;
private Boolean customerIsSupplier;
private Boolean customerIsOwner;
private Boolean customerIsDrawer;
private Serializable customerContact;
private Serializable customerContactPosition;
private Serializable customerAddress1;
private Serializable customerAddress2;
private Serializable customerTown;
private Serializable customerCounty;
private Serializable customerPostCode;
private Serializable customerCountry;
private Serializable customerTelNo;
private Serializable customerFaxNo;
private Serializable customerEmail1;
private Serializable customerEmail2;
private Serializable customerEmail3;
private Serializable customerEmail4;
private Serializable customerEmail5;
private Serializable customerInvoiceName;
private Serializable customerInvoiceAddress1;
private Serializable customerInvoiceAddress2;
private Serializable customerInvoiceTown;
private Serializable customerInvoiceCounty;
private Serializable customerInvoicePostCode;
private Serializable customerInvoiceCountry;
private Serializable customerDefermentAccountNo;
private Double customerBond;
private Double customerBondTrigger;
private Double customerBondRemaining;
private Serializable customerNotes;
private Integer customerCustomerGroupId;
private Serializable customerRdcocode;
private Serializable customerVatregNo;
private Boolean customerIsHoldingAccount;
private Set<TblContacts> tblContactses = new HashSet(0);
private Set<TblMovementCustomers> tblMovementCustomerses = new HashSet(0);
private Set<TblTas2orderConfig> tblTas2orderConfigsForTas2ocCarrierNumber = new HashSet(0);
private Set<TblJournalCustomers> tblJournalCustomerses = new HashSet(0);
private Set<TblTas2orderConfig> tblTas2orderConfigsForTas2ocCustomerNumber = new HashSet(0);
private Set<TblSites> tblSiteses = new HashSet(0);
private Set<TblWomovements> tblWomovementses = new HashSet(0);
private Set<TblTas2destinations> tblTas2destinationses = new HashSet(0);
private Set<TblTas2orderConfig> tblTas2orderConfigsForTas2ocSupplierNumber = new HashSet(0);
private Set<TblTas2orderProduct> tblTas2orderProducts = new HashSet(0);
private Set<TblCustomerStocks> tblCustomerStockses = new HashSet(0);
public TblCustomers() {
}
public TblCustomers(TblFrequency tblFrequency, Boolean customerLocked, Boolean customerDeleted,
Serializable customerCode, Serializable customerName, Boolean customerIsOperator,
Boolean customerIsSupplier, Boolean customerIsOwner, Boolean customerIsDrawer, Serializable customerContact,
Serializable customerContactPosition, Serializable customerAddress1, Serializable customerAddress2,
Serializable customerTown, Serializable customerCounty, Serializable customerPostCode,
Serializable customerCountry, Serializable customerTelNo, Serializable customerFaxNo,
Serializable customerEmail1, Serializable customerEmail2, Serializable customerEmail3,
Serializable customerEmail4, Serializable customerEmail5, Serializable customerInvoiceName,
Serializable customerInvoiceAddress1, Serializable customerInvoiceAddress2,
Serializable customerInvoiceTown, Serializable customerInvoiceCounty, Serializable customerInvoicePostCode,
Serializable customerInvoiceCountry, Serializable customerDefermentAccountNo, Double customerBond,
Double customerBondTrigger, Double customerBondRemaining, Serializable customerNotes,
Integer customerCustomerGroupId, Serializable customerRdcocode, Serializable customerVatregNo,
Boolean customerIsHoldingAccount, Set tblContactses, Set tblMovementCustomerses,
Set tblTas2orderConfigsForTas2ocCarrierNumber, Set tblJournalCustomerses,
Set tblTas2orderConfigsForTas2ocCustomerNumber, Set tblSiteses, Set tblWomovementses,
Set tblTas2destinationses, Set tblTas2orderConfigsForTas2ocSupplierNumber, Set tblTas2orderProducts,
Set tblCustomerStockses) {
this.tblFrequency = tblFrequency;
this.customerLocked = customerLocked;
this.customerDeleted = customerDeleted;
this.customerCode = customerCode;
this.customerName = customerName;
this.customerIsOperator = customerIsOperator;
this.customerIsSupplier = customerIsSupplier;
this.customerIsOwner = customerIsOwner;
this.customerIsDrawer = customerIsDrawer;
this.customerContact = customerContact;
this.customerContactPosition = customerContactPosition;
this.customerAddress1 = customerAddress1;
this.customerAddress2 = customerAddress2;
this.customerTown = customerTown;
this.customerCounty = customerCounty;
this.customerPostCode = customerPostCode;
this.customerCountry = customerCountry;
this.customerTelNo = customerTelNo;
this.customerFaxNo = customerFaxNo;
this.customerEmail1 = customerEmail1;
this.customerEmail2 = customerEmail2;
this.customerEmail3 = customerEmail3;
this.customerEmail4 = customerEmail4;
this.customerEmail5 = customerEmail5;
this.customerInvoiceName = customerInvoiceName;
this.customerInvoiceAddress1 = customerInvoiceAddress1;
this.customerInvoiceAddress2 = customerInvoiceAddress2;
this.customerInvoiceTown = customerInvoiceTown;
this.customerInvoiceCounty = customerInvoiceCounty;
this.customerInvoicePostCode = customerInvoicePostCode;
this.customerInvoiceCountry = customerInvoiceCountry;
this.customerDefermentAccountNo = customerDefermentAccountNo;
this.customerBond = customerBond;
this.customerBondTrigger = customerBondTrigger;
this.customerBondRemaining = customerBondRemaining;
this.customerNotes = customerNotes;
this.customerCustomerGroupId = customerCustomerGroupId;
this.customerRdcocode = customerRdcocode;
this.customerVatregNo = customerVatregNo;
this.customerIsHoldingAccount = customerIsHoldingAccount;
this.tblContactses = tblContactses;
this.tblMovementCustomerses = tblMovementCustomerses;
this.tblTas2orderConfigsForTas2ocCarrierNumber = tblTas2orderConfigsForTas2ocCarrierNumber;
this.tblJournalCustomerses = tblJournalCustomerses;
this.tblTas2orderConfigsForTas2ocCustomerNumber = tblTas2orderConfigsForTas2ocCustomerNumber;
this.tblSiteses = tblSiteses;
this.tblWomovementses = tblWomovementses;
this.tblTas2destinationses = tblTas2destinationses;
this.tblTas2orderConfigsForTas2ocSupplierNumber = tblTas2orderConfigsForTas2ocSupplierNumber;
this.tblTas2orderProducts = tblTas2orderProducts;
this.tblCustomerStockses = tblCustomerStockses;
}
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "customerId", unique = true, nullable = false)
public Integer getCustomerId() {
return this.customerId;
}
public void setCustomerId(Integer customerId) {
this.customerId = customerId;
}
#Column(name = "customerCode")
public Serializable getCustomerCode() {
return this.customerCode;
}
public void setCustomerCode(Serializable customerCode) {
this.customerCode = customerCode;
}
#Column(name = "customerName")
public Serializable getCustomerName() {
return this.customerName;
}
public void setCustomerName(Serializable customerName) {
this.customerName = customerName;
}
Console Output (hibernate.show_sql = true)
DEBUG - begin
DEBUG - Obtaining JDBC connection
DEBUG - Obtained JDBC connection
DEBUG - initial autocommit status: false
DEBUG - Executing identity-insert immediately
DEBUG - insert into TAS.dbo.tblCustomers (customerAddress1, customerAddress2, customerBond, customerBondRemaining, customerBondTrigger, customerCode, customerContact, customerContactPosition, customerCountry, customerCounty, customer_customerGroupId, customerDefermentAccountNo, customerDeleted, customerEmail1, customerEmail2, customerEmail3, customerEmail4, customerEmail5, customerFaxNo, customerInvoiceAddress1, customerInvoiceAddress2, customerInvoiceCountry, customerInvoiceCounty, customerInvoiceName, customerInvoicePostCode, customerInvoiceTown, customerIsDrawer, customerIsHoldingAccount, customerIsOperator, customerIsOwner, customerIsSupplier, customerLocked, customerName, customerNotes, customerPostCode, customerRDCOCode, customerTelNo, customerTown, customerVATRegNo, customerFrequencyId) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into TAS.dbo.tblCustomers (customerAddress1, customerAddress2, customerBond, customerBondRemaining, customerBondTrigger, customerCode, customerContact, customerContactPosition, customerCountry, customerCounty, customer_customerGroupId, customerDefermentAccountNo, customerDeleted, customerEmail1, customerEmail2, customerEmail3, customerEmail4, customerEmail5, customerFaxNo, customerInvoiceAddress1, customerInvoiceAddress2, customerInvoiceCountry, customerInvoiceCounty, customerInvoiceName, customerInvoicePostCode, customerInvoiceTown, customerIsDrawer, customerIsHoldingAccount, customerIsOperator, customerIsOwner, customerIsSupplier, customerLocked, customerName, customerNotes, customerPostCode, customerRDCOCode, customerTelNo, customerTown, customerVATRegNo, customerFrequencyId) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
DEBUG - Natively generated identity: 37
DEBUG - committing
DEBUG - Processing flush-time cascades
DEBUG - Dirty checking collections
DEBUG - Collection found: [com.xpagesbeast.data.entities.enh.TblCustomers.tblContactses#37], was: [<unreferenced>] (initialized)
DEBUG - Collection found: [com.xpagesbeast.data.entities.enh.TblCustomers.tblCustomerStockses#37], was: [<unreferenced>] (initialized)
DEBUG - Collection found: [com.xpagesbeast.data.entities.enh.TblCustomers.tblJournalCustomerses#37], was: [<unreferenced>] (initialized)
DEBUG - Collection found: [com.xpagesbeast.data.entities.enh.TblCustomers.tblMovementCustomerses#37], was: [<unreferenced>] (initialized)
DEBUG - Collection found: [com.xpagesbeast.data.entities.enh.TblCustomers.tblSiteses#37], was: [<unreferenced>] (initialized)
DEBUG - Collection found: [com.xpagesbeast.data.entities.enh.TblCustomers.tblTas2destinationses#37], was: [<unreferenced>] (initialized)
DEBUG - Collection found: [com.xpagesbeast.data.entities.enh.TblCustomers.tblTas2orderConfigsForTas2ocCarrierNumber#37], was: [<unreferenced>] (initialized)
DEBUG - Collection found: [com.xpagesbeast.data.entities.enh.TblCustomers.tblTas2orderConfigsForTas2ocCustomerNumber#37], was: [<unreferenced>] (initialized)
DEBUG - Collection found: [com.xpagesbeast.data.entities.enh.TblCustomers.tblTas2orderConfigsForTas2ocSupplierNumber#37], was: [<unreferenced>] (initialized)
DEBUG - Collection found: [com.xpagesbeast.data.entities.enh.TblCustomers.tblTas2orderProducts#37], was: [<unreferenced>] (initialized)
DEBUG - Collection found: [com.xpagesbeast.data.entities.enh.TblCustomers.tblWomovementses#37], was: [<unreferenced>] (initialized)
DEBUG - Flushed: 0 insertions, 0 updates, 0 deletions to 1 objects
DEBUG - Flushed: 11 (re)creations, 0 updates, 0 removals to 11 collections
DEBUG - Listing entities:
DEBUG - com.xpagesbeast.data.entities.enh.TblCustomers{customerInvoicePostCode=null, customerContactPosition=null, customerDefermentAccountNo=null, tblCustomerStockses=[], tblTas2destinationses=[], customerIsDrawer=null, customerInvoiceCountry=null, tblContactses=[], customerCustomerGroupId=null, tblWomovementses=[],
customerName=TEST XXX, customerDeleted=null,customerBondTrigger=null, customerTown=null, customerVatregNo=null, tblMovementCustomerses=[], tblSiteses=[], tblTas2orderConfigsForTas2ocCarrierNumber=[], customerInvoiceName=null,
customerCode=DELETE ME, customerEmail1=null, customerNotes=null, customerEmail3=null, customerEmail2=null, customerCountry=null, customerEmail5=null, customerInvoiceAddress1=null, tblTas2orderConfigsForTas2ocCustomerNumber=[], customerEmail4=null, customerInvoiceAddress2=null, customerIsOwner=null, tblTas2orderProducts=[], customerBondRemaining=null, customerFaxNo=null, customerIsSupplier=null, customerContact=null, customerPostCode=null, customerId=37, customerCounty=null, customerRdcocode=null, customerLocked=null, customerBond=null, tblTas2orderConfigsForTas2ocSupplierNumber=[], customerTelNo=null, customerInvoiceCounty=null, customerIsHoldingAccount=null, tblJournalCustomerses=[], tblFrequency=null, customerIsOperator=null, customerAddress1=null, customerAddress2=null, customerInvoiceTown=null}
DEBUG - Inserting collection: [com.xpagesbeast.data.entities.enh.TblCustomers.tblContactses#37]
DEBUG - Collection was empty
DEBUG - committed JDBC Connection
main.java closing hibernate session.
DEBUG - Releasing JDBC connection
DEBUG - Released JDBC connection
main.java session closed.
DEBUG - Connection pool now considered primed; min-size will be maintained
Change the fields in your entity class TblCustomers, whose type are serializable to String.
For eg: change
private Serializable customerCode;
to
private String customerCode;
Change the corresponding setter and getter methods as well.
Then try running your application.
Related
For some reason with this setup, when saving the transaction with a nested ticket. It will create both and then connect the two. However when I use the transaction repository to find the transaction it will have an attached ticket however when I use the ticket repository and find the ticket, it doesn't have the attached transaction. I generated this relationship with jhipster jdl, not sure what is going wrong here.
Transaction.java
...
#JsonIgnoreProperties(value = { "person", "event", "transaction", "nameTags" }, allowSetters = true)
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(unique = true)
private Ticket tickets;
public Ticket getTickets() {
return this.tickets;
}
public Transaction tickets(Ticket ticket) {
this.setTickets(ticket);
return this;
}
public void setTickets(Ticket ticket) {
this.tickets = ticket;
}
...
Ticket.java
...
#JsonIgnoreProperties(value = { "tickets", "membershipLevel", "person", "event" }, allowSetters = true)
#OneToOne(mappedBy = "tickets")
private Transaction transaction;
public Transaction getTransaction() {
return this.transaction;
}
public Ticket transaction(Transaction transaction) {
this.setTransaction(transaction);
return this;
}
public void setTransaction(Transaction transaction) {
if (this.transaction != null) {
this.transaction.setTickets(null);
}
if (transaction != null) {
transaction.setTickets(this);
}
this.transaction = transaction;
}
...
Edit:
Here is the generated SQL output, it is showing here just a normal select wihtout joins from both but transaction has the ticket_id in the transaction table while ticket is doing the same but has no reference and would need to do a join but is not.
Hibernate: insert into ticket (cost_per_ticket, count, event_id, person_id, picked_up, id) values (?, ?, ?, ?, ?, ?)
Hibernate: insert into transaction (cost_sub_items_purchased, date, donation, event_id, event_donation, generic_sub_items_purchased, membership_level_id, notes, number_of_memberships, person_id, tickets_id, total_amount, id) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate: select transactio0_.id as id1_23_, transactio0_.cost_sub_items_purchased as cost_sub2_23_, transactio0_.date as date3_23_, transactio0_.donation as donation4_23_, transactio0_.event_id as event_i10_23_, transactio0_.event_donation as event_do5_23_, transactio0_.generic_sub_items_purchased as generic_6_23_, transactio0_.membership_level_id as members11_23_, transactio0_.notes as notes7_23_, transactio0_.number_of_memberships as number_o8_23_, transactio0_.person_id as person_12_23_, transactio0_.tickets_id as tickets13_23_, transactio0_.total_amount as total_am9_23_ from transaction transactio0_
Hibernate: select ticket0_.id as id1_22_, ticket0_.cost_per_ticket as cost_per2_22_, ticket0_.count as count3_22_, ticket0_.event_id as event_id5_22_, ticket0_.person_id as person_i6_22_, ticket0_.picked_up as picked_u4_22_ from ticket ticket0_
Spring Boot 2.4.0, DB is MySql 8.
Data is fetched every 15 seconds from remote with REST and storing it to MySql DB with saveAll().
Which call the save() method for all the given entities.
All data has set ID.
And I am expecting that if there is no such id at DB - it will be inserted.
If such ID is already presented at DB - it will be updated.
Here is snipped from the console:
Hibernate:
insert
into
iot_entity
(controller_ref, description, device_id, device_ref, entity_type_ref, hw_address, hw_serial, image_ref, inventory_nr, ip6address1, ip6address2, ip_address1, ip_address2, latlng, location, mac_address, name, params, status, tenant, type, id)
values
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
...
2020-12-05 23:18:28.269 ERROR 15752 --- [ restartedMain] o.h.e.jdbc.batch.internal.BatchingBatch : HHH000315: Exception executing batch [java.sql.BatchUpdateException: Duplicate entry '1' for key 'iot_entity.PRIMARY'], SQL: insert into iot_entity (controller_ref, description, device_id, device_ref, entity_type_ref, hw_address, hw_serial, image_ref, inventory_nr, ip6address1, ip6address2, ip_address1, ip_address2, latlng, location, mac_address, name, params, status, tenant, type, id) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
2020-12-05 23:18:28.269 WARN 15752 --- [ restartedMain] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 1062, SQLState: 23000
2020-12-05 23:18:28.269 ERROR 15752 --- [ restartedMain] o.h.engine.jdbc.spi.SqlExceptionHelper : Duplicate entry '1' for key 'iot_entity.PRIMARY'
2020-12-05 23:18:28.269 DEBUG 15752 --- [ restartedMain] o.s.orm.jpa.JpaTransactionManager : Initiating transaction rollback after commit exception
org.springframework.dao.DataIntegrityViolationException: could not execute batch; SQL [insert into iot_entity (controller_ref, description, device_id, device_ref, entity_type_ref, hw_address, hw_serial, image_ref, inventory_nr, ip6address1, ip6address2, ip_address1, ip_address2, latlng, location, mac_address, name, params, status, tenant, type, id) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)]; constraint [iot_entity.PRIMARY]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute batch
Here is how to fetch and to save look like:
#Override
#SneakyThrows
#Scheduled(fixedDelay = 15_000)
#Transactional(propagation = Propagation.REQUIRES_NEW)
public void fetchAndStoreData() {
IotEntity[] entities = restTemplate.getForObject(properties.getIotEntitiesUrl(), IotEntity[].class);
log.debug("ENTITIES:\n{}", mapper.writerWithDefaultPrettyPrinter().writeValueAsString(entities));
if (entities != null && entities.length > 0) {
entityRepository.saveAll(List.of(entities));
} else {
log.warn("NO entities data FETCHED !!!");
}
}
This method runs every 15 seconds.
Entity:
#Data
#Entity
#NoArgsConstructor
#EqualsAndHashCode(of = {"id"})
#ToString(of = {"id", "deviceId", "entityTypeRef", "ipAddress1"})
public class IotEntity implements Serializable {
private static final long serialVersionUID = 1L;
#Id
private Integer id;
// other fields
and Repository:
public interface EntityRepository extends JpaRepository<IotEntity, Integer> {
}
Here is snipped for iot entity at JSON format:
2020-12-05 23:18:44.261 DEBUG 15752 --- [pool-3-thread-1] EntityService : ENTITIES:
[ {
"id" : 1,
"controllerRef" : null,
"name" : "Local Controller Unterföhring",
"description" : "",
"deviceId" : "",
...
So ID is definitely set.
Also, batching is enabled for a project. It shouldn't have any impact on saving.
I could not understand why it tries to insert a new entity instead of update the existing one?
Why it couldn't distinguish the difference between the old and new entities?
UPDATE:
Implemented Persistable for Entity:
#Data
#Entity
#NoArgsConstructor
#EqualsAndHashCode(of = {"id"})
#ToString(of = {"id", "deviceId", "entityTypeRef", "ipAddress1"})
public class IotEntity implements Serializable, Persistable<Integer> {
private static final long serialVersionUID = 1L;
#Id
private Integer id;
#Override
public boolean isNew() {
return false;
}
#Override
public Integer getId() {
return this.id;
}
However, it fails with the same exception - Duplicate entry '1' for key 'iot_entity.PRIMARY'
If I will add #GeneratedValue like the following:
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
It wouldn't fail. However, it will update the ID value by itself.
For example, it fetched with id = 15:
[ {
"id" : 15,
"carParkRef" : 15,
"name" : "UF Haus 1/2",
And should be saved like following:
In fact it has id = 2 instead:
And it is incorrect.
Tried to add to storing service:
private final EntityManager entityManager;
...
List.of(carParks).forEach(entityManager::merge);
Fails with the same exception (with or without implementing Persistable). It tries to insert the value - insert into ... Duplicate entry '15' for key '... .PRIMARY'
Snippet from application.yml:
spring:
# ===============================
# = DATA SOURCE
# ===============================
datasource:
url: jdbc:mysql://localhost:3306/demo_db
username: root
password: root
initialization-mode: always
# ===============================
# = JPA / HIBERNATE
# ===============================
jpa:
show-sql: true
generate-ddl: true
hibernate:
ddl-auto: update
properties:
hibernate:
format_sql: true
generate_statistics: true
Here you could see pom file content.
How to fix this issue?
The problem is likely that, since the #Id is not marked with #GeneratedValue, Spring Data assumes all detached (transient) entities passed to save()/saveAll() should have EntityManager.persist() invoked on them.
Try making IotEntity implement Persistable and returning false from isNew(). This will tell Spring Data to always use EntityManager.merge() instead, which should have the desired effect (i.e. inserting nonexistent entities and updating existing ones).
Looks like I found the root of this behaviour.
Main App launcher look like:
#AllArgsConstructor
#SpringBootApplication
public class Application implements CommandLineRunner {
private final DataService dataService;
private final QrReaderServer qrReaderServer;
private final MonitoringService monitoringService;
#Override
public void run(String... args) {
dataService.fetchAndStoreData();
monitoringService.launchMonitoring();
qrReaderServer.launchServer();
}
All 3 steps have strict execution sequence. And the first one has to repeat for updating data locally if it is needed. Two other just servers which work with stored data only.
Where the first method look like:
#Scheduled(fixedDelay = 15_000)
public void fetchAndStoreData() {
log.debug("START_DATA_FETCH");
carParkService.fetchAndStoreData();
entityService.fetchAndStoreData();
assignmentService.fetchAndStoreData();
permissionService.fetchAndStoreData();
capacityService.fetchAndStoreData();
log.debug("END_DATA_FETCH");
}
Also, this execution is scheduled as well.
When the app starts it tried to execute this fetching twice:
2020-12-14 14:00:46.208 DEBUG 16656 --- [pool-3-thread-1] c.s.s.s.data.impl.DataServiceImpl : START_DATA_FETCH
2020-12-14 14:00:46.208 DEBUG 16656 --- [ restartedMain] c.s.s.s.data.impl.DataServiceImpl : START_DATA_FETCH
2 threads run at the same catch and store in parallel - trying to insert data. (tables are recreated at every start).
All later fetches are fine, they are executed only by #Sceduled thread.
If comment #Sceduled - it will work fine without any Exceptions.
SOLUTION:
Added additional boolean property to service class:
#Getter
private static final AtomicBoolean ifDataNotFetched = new AtomicBoolean(true);
#Override
#Scheduled(fixedDelay = 15_000)
#Order(value = Ordered.HIGHEST_PRECEDENCE)
public void fetchAndStoreData() {
ifDataNotFetched.set(true);
log.debug("START_DATA_FETCH");
// fetch and store data with `saveAll()`
log.debug("END_DATA_FETCH");
ifDataNotFetched.set(false);
}
And control the value after the application is started:
#Value("${sharepark.remote-data-fetch-timeout}")
private int dataFetchTimeout;
private static int fetchCounter;
#Override
public void run(String... args) {
waitRemoteDataStoring();
monitoringService.launchMonitoring();
qrReaderServer.launchServer();
}
private void waitRemoteDataStoring() {
do {
try {
if (fetchCounter == dataFetchTimeout) {
log.warn("Data fetch timeout reached: {}", dataFetchTimeout);
}
Thread.sleep(1_000);
++fetchCounter;
log.debug("{} Wait for data fetch one more second...", fetchCounter);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
} while (DataServiceImpl.getIfDataNotFetched().get() && fetchCounter <= dataFetchTimeout);
}
Spring Data JPA uses combination of #version #Id field to decide the whether to merge or insert.
null #id and null #version would mean new record hence insert
if #id is present #version field is used to decide whether to merge or insert.
Update is only invoked when (update .... where id = xxx and version = 0)
Beacuse you have #id and #version missing, its trying to insert, because underlysing system decided this is new record and when run sql u get error.
Can you pls try with #GeneratedValue(strategy = GenerationType.AUTO)
This worked for me.
I am inserting a row into an Oracle table in a Spring Boot application. The Primary Key needs to be generated using annotations. I have an entity model that represents the table:
#Entity
#Table(name="PURCH_TENDR")
public class LhlPurchTendrModel implements Serializable {
#Id
#GeneratedValue(generator = "uuid2")
#GenericGenerator(name = "uuid2", strategy = "org.hibernate.id.UUIDGenerator")
#Column(name="PURCH_TENDR_ID")
private String purchTendrId;
#Column(name="CREATED_BY_NM")
private String createdByNm;
#Column(name="CREATED_DT")
private Timestamp createdDt;
#Column(name="UPDATED_BY_NM")
private String updatedByNm;
#Column(name="UPDATED_DT")
private Timestamp updatedDt;
#Column(name="MODIFY_BY_NM")
private String modifyByNm;
#Column(name="MODIFY_DT")
private Timestamp modifyDt;
#Column(name="CARRIER_TENDER_ID")
private long CarrierTenderId;
#Column(name="EVENT_GMT_TM")
private Timestamp EventGmtTm;
#Column(name="PURCH_COST_ID")
private int PurchCostId;
#Column(name="LAT")
private float Lat;
#Column(name="LON")
private float Lon;
#Column(name="CITY_NM")
private String cityNm;
#Column(name="STATE_CD")
private String stateCd;
#Column(name="CARER_EDI_NBR")
private String carerEdiNbr;
#Column(name="EVENT_STAT_CD")
private String eventStatCd;
#Column(name="ETN_TM")
private Timestamp EtnTm;
#Column(name="PCKUP_NBR")
private String PickupNbr;
#Column(name="VIN")
private String Vin;
#Column(name="EQUIP_NBR")
private String EquipNbr;
#Column(name="EQUIP_PREFIX")
private String EquipPrefix;
There are also getters and setters for these member variables.
I use a Repository class to implements a jdbctemplate to insert the row.
When I use this variation of the insert, I get the error that the column type is invalid:
public boolean insertPurchaseInfo(LhlPurchTendrModel lhlPurchTendrModel) throws SQLException {
boolean success= false;
String ds = lhlJdbcTemplate.getDataSource().getConnection().getSchema();
LOGGER.info("Schema and Insert Purchase Info {}", ds);
String insertSequenceNbrSQLStatement = "INSERT INTO purch_tendr(created_by_nm, created_dt, modify_by_nm, modify_dt, carrier_tender_id, purch_cost_id, event_stat_cd, equip_nbr, equip_prefix) " +
"VALUES (?, SYSDATE, ?, SYSDATE, ?, ?, ?, ?, ?)";
try{
int rowsInserted = lhlJdbcTemplate.update(
insertSequenceNbrSQLStatement,
new Object[] {lhlPurchTendrModel});
if(rowsInserted > 0){
success = true;
}
}
When I try to insert using this code, I get the error 'cannot insert NULL into table Purch_Tendr column Purch_Tendr_Id.
public boolean insertPurchaseInfo(LhlPurchTendrModel lhlPurchTendrModel) throws SQLException {
boolean success= false;
String ds = lhlJdbcTemplate.getDataSource().getConnection().getSchema();
LOGGER.info("Schema and Insert Purchase Info {}", ds);
String insertSequenceNbrSQLStatement = "INSERT INTO purch_tendr(created_by_nm, created_dt, modify_by_nm, modify_dt, carrier_tender_id, purch_cost_id, event_stat_cd, equip_nbr, equip_prefix) " +
"VALUES (?, SYSDATE, ?, SYSDATE, ?, ?, ?, ?, ?)";
try{
int rowsInserted = lhlJdbcTemplate.update(
insertSequenceNbrSQLStatement,
new Object[]{lhlPurchTendrModel.getCreatedByNm(), lhlPurchTendrModel.getModifyByNm(), lhlPurchTendrModel.getCarrierTenderId(), lhlPurchTendrModel.getPurchCostId(),
lhlPurchTendrModel.getEventGmtTm(), lhlPurchTendrModel.getEquipNbr(), lhlPurchTendrModel.getEquipPrefix()});
if(rowsInserted > 0){
success = true;
}
}
I am not sure how to use the #Entity class with JdbcTemplate. How do I indicate to JdbcTemplate to generate the primary key value?
You can't because #Entity and all annotations you use such as #GeneratedValue, #GenericGenerator etc come from JPA while JdbcTemplate behind scene is based on JDBC only which does not know anything about JPA.
If you want to use JPA to manage your data , what you need to look is to choose a JPA implementation (e.g Hibernate is a popular one) and study how to use it through JPA interface but not looking at JdbcTemplate.
Once you get the basic ideas to manage data using JPA , you may consider to look at spring data which is a more high level tool build on top of pure JPA that can help to implement repository / DAO kind of stuff for managing and querying the data.
I have the following entity which has a relation with WorkFlowDetail class:
#Entity()
#DynamicUpdate()
#Table(schema = "RACQUISTI", name = "RICHIESTA_DI_ACQUISTO")
public class RichiestaDiAcquisto {
#Id
#Column(name = "ID_RICHIESTA_ACQUISTO")
#SequenceGenerator(name="SEQ_GEN",sequenceName="RICHIESTA_DI_ACQUISTO_SEQ", allocationSize=1)
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SEQ_GEN")
private int id;
#OneToOne(fetch=FetchType.LAZY, cascade = {CascadeType.ALL})
#JoinColumn(name="ID_RICHIESTA_ACQUISTO")
private WorkFlowDetail workFlowDetail;
.....
}
The WorkFlowDetail entity is:
#Entity()
#Table(schema = "RACQUISTI", name = "WORKFLOW_DETAIL")
public class WorkFlowDetail {
#Id
#Column(name = "ID_RICHIESTA_ACQUISTO")
private int idRichiestaDiAcquisto;
#Column(name = "ID_WORKFLOW_INSTANCE")
private String idWorkFlowInstance;
....
}
The table WORKFLOW_DETAIL has a foreign key on RICHIESTA_DI_ACQUISTO primary key.
When I execute the following code:
RichiestaDiAcquisto entity = new RichiestaDiAcquisto();
getSession().saveOrUpdate(entity);
I receive this error:
Hibernate: select RICHIESTA_DI_ACQUISTO_SEQ.nextval from dual
Hibernate: select workflowde_.ID_RICHIESTA_ACQUISTO, workflowde_.CURRENT_NODE_ID as CURRENT_2_2_, workflowde_.DATA_MOD as DATA_MOD3_2_, workflowde_.ID_WORKFLOW_INSTANCE as ID_WORKF4_2_, workflowde_.WORKFLOW_TOKEN as WORKFLOW5_2_ from RACQUISTI.WORKFLOW_DETAIL workflowde_ where workflowde_.ID_RICHIESTA_ACQUISTO=?
Hibernate: select richiedent_.ID_RICHIESTA_ACQUISTO, richiedent_.COGNOME as COGNOME2_0_, richiedent_.GODIVA_ANAGRAFICA_ID as GODIVA_A3_0_, richiedent_.NOME as NOME4_0_ from RACQUISTI.RICHIEDENTE richiedent_ where richiedent_.ID_RICHIESTA_ACQUISTO=?
Hibernate: insert into RACQUISTI.RICHIESTA_DI_ACQUISTO (ACQUISTO_DI_BENI, CONFERMA_CAPITOLO, CONFERMA_ELEGIBILITA, COSTO_ACQUISTO, DATA_MOD, DESCRIZIONE_ACQUISTO, GARA_NAZIONALE_CATALOGO, ID_ANAG_MOD, LUOGO_DI_CONSEGNA, SIGLA_ESPERIMENTO, STATUS, STRUTTURA_PAGANTE, ID_RICHIESTA_ACQUISTO) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into RACQUISTI.WORKFLOW_DETAIL (CURRENT_NODE_ID, DATA_MOD, ID_WORKFLOW_INSTANCE, WORKFLOW_TOKEN, ID_RICHIESTA_ACQUISTO) values (?, ?, ?, ?, ?)
WARN 2017-04-28 10:14:28,817 [http-nio-8080-exec-6] org.hibernate.engine.jdbc.spi.SqlExceptionHelper - SQL Error: 2291, SQLState: 23000
ERROR 2017-04-28 10:14:28,819 [http-nio-8080-exec-6] org.hibernate.engine.jdbc.spi.SqlExceptionHelper - ORA-02291: integrity constraint (RACQUISTI.WORKFLOW_DETAIL_FK1) violated - parent key not found
Your insert statement is trying to insert a value into column which doesn't exist in the RACQUISTI table
I found a solution. I modify the annotation on main class child (WorkFlowDetail):
#Entity()
#DynamicUpdate()
#Table(schema = "RACQUISTI", name = "RICHIESTA_DI_ACQUISTO")
public class RichiestaDiAcquisto {
#Id
#Column(name = "ID_RICHIESTA_ACQUISTO")
#SequenceGenerator(name="SEQ_GEN",sequenceName="RICHIESTA_DI_ACQUISTO_SEQ", allocationSize=1)
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SEQ_GEN")
private int id;
#OneToOne(fetch=FetchType.LAZY, mappedBy = "richiestaDiAcquisto", cascade = {CascadeType.ALL})
private WorkFlowDetail workFlowDetail;
.....
}
Then I modified the child class:
#Entity()
#Table(schema = "RACQUISTI", name = "WORKFLOW_DETAIL")
public class WorkFlowDetail {
#GenericGenerator(name = "generator", strategy = "foreign",
parameters = #org.hibernate.annotations.Parameter(name = "property", value = "richiestaDiAcquisto"))
#Id
#GeneratedValue(generator = "generator")
#Column(name = "ID_RICHIESTA_ACQUISTO", unique = true, nullable = false)
private int idRichiestaAcquisto;
#OneToOne(fetch = FetchType.LAZY)
#PrimaryKeyJoinColumn
private RichiestaDiAcquisto richiestaDiAcquisto;
....
}
Before to save the main class (RichiestaDiAcquisto) I have to put the father on the child class by the following code:
richiestaDiAcquisto.getWorkFlowDetail().setRichiestaDiAcquisto(richiestaDiAcquisto);
I have a problem when trying to persist new entities. I'm using Eclipselink 2.4.2 as entity manager. My BaseDao class in the store method flushes and refreshes entity after persisting it as new (persist->flush->refresh). All is happening in a single transaction.
My entities look like this (the part I'm concerned about):
TrustEntity {
#OneToMany(fetch = FetchType.LAZY, mappedBy = "trust", cascade = {CascadeType.ALL})
#PrivateOwned
private List<TrustIncentiveRateEntity> trustIncentiveRates;
}
TrustIncentiveRateEntity {
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "TRUST_ID", nullable = false)
private TrustEntity trust;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "trustIncentiveRate", cascade = {CascadeType.ALL})
#PrivateOwned
private List<TrustIncentiveRateValueEntity> trustIncentiveRateValues;
}
TrustIncentiveRateValueEntity {
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "TRUST_INCENTIVE_RATE_ID", nullable = false)
private TrustIncentiveRateEntity trustIncentiveRate;
}
I'm creating a new Trust entity, instantiate a TrustIncentiveRateEntity list, create one new element in it, instantiate a TrustIncentiveRateEntity and create one new element in it.
During debugging I could see that all the references, in both ways, are correct.
Now, when I try to persist this here is what happens:
Log from server:
FINE: SELECT SEQ_TRUST.NEXTVAL FROM DUAL
FINE: SELECT SEQ_TRUST_INCENTIVE_RATE.NEXTVAL FROM DUAL
FINE: SELECT SEQ_TRUST_INCENTIVE_RATE_VALUE.NEXTVAL FROM DUAL
FINE: INSERT INTO TRUST (TRUST_ID, ACTION_DATE, ACTION_USER_ID, IS_ACTIVE, CREATION_DATE, CREATION_USER_ID, IS_INCENTIVE_ACTIVE, IS_NO_CREDIT_LIMIT, PROCESS_CURRENT_STATUS, REMARKS, STATUS_INCENTIVE, TRUST_CODE, TRUST_NAME, TRUST_TYPE, UPDATE_DATE, UPDATE_USER_ID, VERSION_OPT_LOCK, STRUCTURAL_ORG_UNIT_SALES_ID, STRUCTURAL_ORG_UNIT_ID, USER_ID) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
bind => [38007, 2013-04-26 09:46:31.582, 1003186, true, 2013-04-26 07:46:34.659, 1003186, true, false, OPEN, null, OPEN, 100058, 741963852, T, null, null, 1, 387, 387, 1003186]
FINE: INSERT INTO TRUST_INCENTIVE_RATE (TRUST_INCENTIVE_RATE_ID, CREATION_DATE, CREATION_USER_ID, EQUIPMENT_SIZE, EXTENDED_EQ_GROUP_ID, RATE_BASIS, UPDATE_DATE, UPDATE_USER_ID, VERSION_OPT_LOCK, TRADE_ID, TRUST_ID) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
bind => [15001, 2013-04-26 07:46:39.862, 1003186, 20, 2, B, null, null, 1, 144001, 38007]
FINE: INSERT INTO TRUST_INCENTIVE_RATE_VALUE (TRUST_INCENTIVE_RATE_VALUE_ID, CREATION_DATE, CREATION_USER_ID, EFFECTIVE_DATE, EXPIRY_DATE, INCENTIVE, STATUS, UPDATE_DATE, UPDATE_USER_ID, VERSION_OPT_LOCK, CURRENCY_CODE, TRUST_INCENTIVE_RATE_ID) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
bind => [14007, 2013-04-26 07:46:39.955, 1003186, 2013-04-26 00:00:00.0, 9999-12-31 00:00:00.0, 12, OPEN, null, null, 1, USD, 15001]
FINE: SELECT TRUST_ID, ACTION_DATE, ACTION_USER_ID, IS_ACTIVE, CREATION_DATE, CREATION_USER_ID, IS_INCENTIVE_ACTIVE, IS_NO_CREDIT_LIMIT, PROCESS_CURRENT_STATUS, REMARKS, STATUS_INCENTIVE, TRUST_CODE, TRUST_NAME, TRUST_TYPE, UPDATE_DATE, UPDATE_USER_ID, VERSION_OPT_LOCK, STRUCTURAL_ORG_UNIT_SALES_ID, STRUCTURAL_ORG_UNIT_ID, USER_ID FROM TRUST WHERE (TRUST_ID = ?)
bind => [38007]
FINE: SELECT TRUST_INCENTIVE_RATE_ID, CREATION_DATE, CREATION_USER_ID, EQUIPMENT_SIZE, EXTENDED_EQ_GROUP_ID, RATE_BASIS, UPDATE_DATE, UPDATE_USER_ID, VERSION_OPT_LOCK, TRADE_ID, TRUST_ID FROM TRUST_INCENTIVE_RATE WHERE (TRUST_ID = ?)
bind => [38007]
FINE: SELECT TRUST_INCENTIVE_RATE_VALUE_ID, CREATION_DATE, CREATION_USER_ID, EFFECTIVE_DATE, EXPIRY_DATE, INCENTIVE, STATUS, UPDATE_DATE, UPDATE_USER_ID, VERSION_OPT_LOCK, CURRENCY_CODE, TRUST_INCENTIVE_RATE_ID FROM TRUST_INCENTIVE_RATE_VALUE WHERE (TRUST_INCENTIVE_RATE_ID = ?)
bind => [15001]
So far so good, but when the transaction is commited by EntityManager I get the following exception:
WARNING: java.lang.IllegalStateException: During synchronization a new object was found through a relationship that was not marked cascade PERSIST: my.package.entity.TrustIncentiveRateEntity#1fa1df7.
at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.discoverUnregisteredNewObjects(RepeatableWriteUnitOfWork.java:303)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.calculateChanges(UnitOfWorkImpl.java:706)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabaseWithChangeSet(UnitOfWorkImpl.java:1498)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.issueSQLbeforeCompletion(UnitOfWorkImpl.java:3151)
at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.issueSQLbeforeCompletion(RepeatableWriteUnitOfWork.java:345)
at org.eclipse.persistence.transaction.AbstractSynchronizationListener.beforeCompletion(AbstractSynchronizationListener.java:158)
at org.eclipse.persistence.transaction.JTASynchronizationListener.beforeCompletion(JTASynchronizationListener.java:68)
at com.sun.enterprise.transaction.JavaEETransactionImpl.commit(JavaEETransactionImpl.java:435)
at com.sun.enterprise.transaction.JavaEETransactionManagerSimplified.commit(JavaEETransactionManagerSimplified.java:855)
at com.sun.ejb.containers.BaseContainer.completeNewTx(BaseContainer.java:5136)
at com.sun.ejb.containers.BaseContainer.postInvokeTx(BaseContainer.java:4901)
at com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:2045)
at com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:1994)
at com.sun.ejb.containers.EJBLocalObjectInvocationHandler.invoke(EJBLocalObjectInvocationHandler.java:222)
at com.sun.ejb.containers.EJBLocalObjectInvocationHandlerDelegate.invoke(EJBLocalObjectInvocationHandlerDelegate.java:88)
at $Proxy241.save(Unknown Source)
Which for me seems strange, like the EM tries to actually store TrustIncentiveRateValueEntity before TrustIncentiveRateEntity and can't see TrustIncentiveRateEntity.
After looking at similar threads I've added CascadeType.PERSIST to the #ManyToOne annotation over trustIncentiveRate field in TrustIncentiveRateValueEntity class. After that the situation looks like this: EM inserts the entities like before AND THEN it gets nextval from SEQ_TRUST_INCENTIVE_RATE and tries to insert TrustIncentiveRateValueEntity again (with the new id, but the rest of the field values remain the same). It results in constrain violation, as I have a unique constrain on cross-section of some of this table columns. Exception, transaction rolled back, I am still sad.
My store method in the BaseDao class:
#TransactionAttribute(TransactionAttributeType.MANDATORY)
public T_ENTITY store(T_ENTITY entity) {
if (!entity.isNewlyCreated()) {
T_ENTITY mergedEntity = em.merge(entity);
flush();
return mergedEntity;
} else {
try {
em.persist(entity);
flush();
refresh();
} catch (RuntimeException exc) {
entity.resetPersistentFlag();
throw exc;
}
return entity;
}
}
But calling the em.persist(entity) directly, without flush/refresh causes the same problem.
The logic of the service call:
#Override
#TransactionAttribute(TransactionAttributeType.REQUIRED)
public TrustEntity save(TrustEntity dto) {
TrustEntity trust = trustDao.store(trust);
workflowConversation.triggerWorkflow(); // doesn't do anything to any of the entities when they are freshly created
return trust;
}
Anybody could help me in identifying what could be wrong with this?
You cannot have a OneToMany that uses both a mappedby, making it bidirectional, and a joincolumn marking it as unidirectional. They conflict and are causing you issues.
When you mark a relationship as mappedby, you specify that all information and control of the relationship is on the other side - that includes the joincolumn info. try:
TrustEntity {
#OneToMany(fetch = FetchType.LAZY, mappedBy = "trust", cascade = {CascadeType.ALL})
#PrivateOwned
private List<TrustIncentiveRateEntity> trustIncentiveRates;
}
TrustIncentiveRateEntity {
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "TRUST_ID", nullable = false)
private TrustEntity trust;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "trustIncentiveRate", cascade = {CascadeType.ALL})
#PrivateOwned
private List<TrustIncentiveRateValueEntity> trustIncentiveRateValues;
}