Repository save() is not committing or persisting data into table and returning an object with primary key which is already in table - oracle

I am writing JPA implementation to replace JDBC implementation with query. I have used the Oracle database sequence object name in #SequenceGenerator as shown in the code. As a result, save() is returning an already existing data in the table instead of generating a new primary key and inserting into the table.
I think the sequence is generating existing primary key instead of generating a new one.
#Entity
#Table(name = "table")
public class TableDetail implements java.io.Serializable{
#Id
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator = "table_seq")
#SequenceGenerator(sequenceName = "SEQ_TABLE", allocationSize = 1, name = "table_seq")
private Long AUDT_ID;
....
}
#Repository
public interface TableDetailDAO extends CrudRepository<TableDetail, Long> {
TableDetail save(TableDetail tableDetail);
}
#Service
#Transactional
public class TableDetailServiceImpl implements TableDetailService {
public void createAuditEvent(TableDetail tableDetail) {
#Autowired
TableDetailDAO tableDetailDAO;
TableDetail tableDetail =
tableDetailDAO.save(tableDetail);
}
}

So I figured out that it was due to my JDBC Database config file where I had defined this TransactionManager as shown. I had to remove this or define a JpaTransactionManager in this method. Right now, this definition was not letting JPA handle the commit due to which the data was not being persisted into the database.
This definition was present because it was actually a JDBC implementation before.
Also, I had to use GenerationType.AUTO because as far as my understanding, GenerationType.SEQUENCE is used only when there is no Sequence object defined in the Database.
/**
* Creates a handle to the TransactionManager.
*
* #return PlatformTransactionManager
*/
#Bean(name = "transactionManager")
public PlatformTransactionManager txManager() {
return new DataSourceTransactionManager(initializeDataSource());
}

Related

Database default field not retrieved when using #Transactional

I have the following simple entity FileRegistry :
#Getter
#Setter
#Entity
#ToString
#Table(name = "file_store")
public class FileRegistry {
#Id
private String name;
/**
* Creation timestamp of the registry
* This value is automatically set by database, so setter method
* has been disabled
*/
#Setter(AccessLevel.NONE)
#Column(insertable = false, updatable = false)
private LocalDateTime creationDate;
}
The following FileRepository DAO:
#Repository
public interface FileRepository extends JpaRepository<FileRegistry, String> { }
and the following Spring Boot test :
#SpringBootTest(classes=PersistTestConfig.class, properties = { "spring.config.name=application,db"})
#ActiveProfiles("test")
#Transactional
public class FileRepositoryTest {
#Autowired
FileRepository fileRepository;
#Test
void insertFileTest() {
assertNotNull(fileRepository, "Error initializing File repository");
// Check registry before insertion
List<FileRegistry> allFiles = fileRepository.findAll();
assertNotNull(allFiles, "Error retrieving files from registry");
assertThat(allFiles.size(), is(0));
// Insert file
FileRegistry fileRegistry = new FileRegistry();
fileRegistry.setName("Test");
fileRepository.save(fileRegistry);
// Check that the insertion was successful
allFiles = fileRepository.findAll();
assertNotNull(allFiles, "Error retrieving files from registry");
assertThat(allFiles.size(), is(1));
assertEquals("File registry name mismatch", "Test", allFiles.get(0).getName());
System.out.println(allFiles.get(0));
}
}
Persistence configuration class defined as follows :
#Configuration
#EnableAutoConfiguration
#EnableTransactionManagement
#EnableJpaRepositories
public class PersistTestConfig {
}
The table file_store defined in H2 as :
CREATE TABLE file_store (name VARCHAR NOT NULL, creation_date TIMESTAMP(3) DEFAULT NOW() NOT NULL, CONSTRAINT file_store_pk PRIMARY KEY (name));
Everything works fine except that when I use #Transactional at test level (mainly to benefit from rollbacks i.e. db cleanup on each test) a null value is fetched for the creationDate field :
FileRegistry(name=Test, creationDate=null)
When I remove #Transactional from the test class, the fetched value contains the date as computed by H2 :
FileRegistry(name=Test, creationDate=2019-03-07T17:08:13.392)
I've tried to flush and merge manually the instance to no avail. To be honest, right now I'm a little bit lost on how #Transactional really works, in fact reading the docs and inspecting the code, the underlying JpaRepository implementation (SimpleJpaRepository) is annotated as #Transactional(readOnly = true).
A little help on this subject would be very appreciated.
Ok, figured it out.
Simply issuing a refresh entityManager.refresh(allFiles.get(0)); solves the issue.
I tested also using Hibernate's #Generated(INSERT) specific annotation in the entity creationDate field and it also worked fine.
By the way I've eventually decided to drop this thing in favor of using Spring Data's JpaAuditing features and annotating the field with #CreatedDate annotation to fill the value instead of relying on DB date (by the way, production-wise, you probably shouldn't rely on DB time). To me this is feels more, let's say, "correct" and springy way of doing things.

Java, Hibernate -- Can't retrieve id after persisting entity with separate embedded key class

I am working on a sample Springboot server application and using hibernate for JPA. I am using a generic repository pattern that performs all the CRUD operations on my entity. I am following this example :
http://www.concretepage.com/spring-boot/spring-boot-rest-jpa-hibernate-mysql-example that I came across. (My idea to have a Generic repository was to have a similar implementation for all CRUD operations, than explicitly stating one in each Service/DAO or repository implementation for each Entity) In the above example the #ID attribute is in the same class as the Entity. As a result of that I was able to persist an entity and the id would be reflected in the object after entityManager.persist(object)
In my code I have the Key class separate and it is referenced in the Entity class. On calling persist on EntityManager, a row is created in the database (since the column for the primary key is set to auto-increment in the database), but that same ID isn't reflected in the object after calling persist(). At all times my ID attribute within the key class is set to 0 that is the default int value. I would like to know if there is a way that I could fetch the ID of the inserted object either through Session or EntityManager. Also is there any alternate strategy to going about this problem without having the include the primary key in the Entity class itself. (As of now, I have looked at multiple posts on SO but haven't been able to get to a solution to my problem.)
Entity class
#Entity
#Table(name = "articles")
public class SampleArticle extends AbstractDomainObject {
/** The serialVersionUID. */
private static final long serialVersionUID = 7072648542528280535L;
/** Uniquely identifies the article. */
#EmbeddedId
#AttributeOverride(name = "articleId", column = #Column(name = "article_id"))
#GeneratedValue(strategy = GenerationType.IDENTITY)
//#GeneratedValue(strategy = GenerationType.AUTO)
private SampleArticleKey key;
/** Indicates the title. */
#Column(name = "title")
private String title;
Key class
#Embeddable
public class SampleArticleKey extends AbstractDomainKey {
/**
* Serial version id.
*/
private static final long serialVersionUID = 1325990987094850016L;
/** The article id. */
private int articleId;
Repository class
#Repository
#Transactional
public class SampleArticleRepository extends
AbstractRepository<SampleArticle, SampleArticleKey> implements
ISampleArticleRepository<SampleArticle, SampleArticleKey> {
/*
* (non-Javadoc)
* #see
* com.wpi.server.entity.repository.ISampleArticleRepository#addArticle
* (java.lang.Object)
*/
#Override
public SampleArticle create(SampleArticle article) throws Exception {
return super.create(article);
}
Abstract Repository
#Transactional
public abstract class AbstractRepository<T extends AbstractDomainObject, K
extends AbstractDomainKey> {
/** The entity manager. */
#PersistenceContext
private EntityManager entityManager;
/** The Constant LOGGER. */
private static final Logger LOGGER = Logger.getLogger(AbstractRepository.class.getName());
/**
* Persist the given object at persistence storage.
*
* #param object
* The object extending {#link AbstractDomainObject} which needs
* to be inserted.
* #return object of type {#link AbstractDomainObject} with the newly
* generated id.
* #throws Exception
* If unable to insert data.
*/
public T create(T object) throws Exception {
final Session session = entityManager.unwrap(Session.class);
session.getTransaction().begin();
session.save(object);
session.flush();
session.getTransaction().commit();
session.close();
LOGGER.fine("Entity CREATED successfully.");
return object;
};
Let me give you a working embeddable key example. It might help.
First overwrite equals() and hashCode() methods so that Hibernate proper identifies objects in the cash.
Now you can persist objects
Let me know if this helps or you have other issues with this.

auditing filelds in spring data

I'm beginner in java programming. And I try to write simple stand alone application with spring data. To basic example which is here http://spring.io/guides/gs/accessing-data-jpa/ I want to add, auditing mechanism which will store previous values for objects. I want in customer entity, on #PreUpdate store old values in another table, but I do not know how.
#Entity
#EntityListeners(AuditingEntityListener.class)
public class Customer implements Serializable {
...
#Transient
private transient Customer savedState;
#PreUpdate
public void onPreUpdate() {
if (!savedState.firstName.equals(this.firstName)) {
log.info(String.format("first name was modified, new value =%s, old value=%s",this.firstName, savedState.firstName ));
}
}
#PostLoad
private void saveState(){
this.savedState = (Customer) SerializationUtils.clone(this); // from apache commons-lang
}

How to handle DataIntegrityVilolationException while saving a list in Spring Data JPA?

I am using Spring Data JPA in a Spring Boot Application, with MYSQL. There I am saving a list of entities with unique constraint over a field. Out of the list of entities, there is one entity that will throw DataIntegrityViolationException due to the unique constraint. I noticed that none of the entities get persisted in that case, even those that does not violate the unique constraint.
What should be the ideal approach in this case so that those entities which do not violate the unique get persisted ?
Of course I can iterate the list and save them one by one. In fact that is what SimpleJpaRepository is doing underneath.
#Transactional
public <S extends T> List<S> save(Iterable<S> entities) {
List<S> result = new ArrayList<S>();
if (entities == null) {
return result;
}
for (S entity : entities) {
result.add(save(entity));
}
return result;
}
My code - Entity :
#Entity
#Table(uniqueConstraints = #UniqueConstraint(columnNames = { "name" }, name = "uq_name"))
public class SampleContent {
#Id
#GeneratedValue
private Long id;
private String name;
//getter setters
}
Repository :
public interface SampleContentRepository extends JpaRepository<SampleContent, Serializable>{
}
JUnit test :
#Test
public void testCreate(){
List<SampleContent> sampleContentList = new ArrayList<>();
SampleContent sampleContent1 = new SampleContent();
sampleContent1.setName("dd");
SampleContent sampleContent2 = new SampleContent();
sampleContent2.setName("Roy");
SampleContent sampleContent3 = new SampleContent();
sampleContent3.setName("xx");
sampleContentList.add(sampleContent1);
sampleContentList.add(sampleContent2);
sampleContentList.add(sampleContent3);
try{
this.sampleContentRepository.save(sampleContentList);
}catch(DataIntegrityViolationException e){
System.err.println("constraint violation!");
}
}
There is an entity with name "Roy" already present in the table. So, the entire transaction fails and #Transactional rolls back.
I think you can use next steps:
Load existing entities from DB into Set
Override equals and hashCode methods based on name
call Set::addAll you antities (or just add them one by one)
save that Set to DB
Maybe it's suboptimal because forces you to make select * query. But I think it's much more effective then saving entities one by one to DB.
Accotding to this article you can use name as your business key, which has lots of benefits.

I need help for persisting into oracle database

There is a problem about generating id while persisting into database.
I added the following code to my jpa entity file, however I'm getting 0 for personid.
#Id
#Column(unique=true, nullable=false, precision=10, name="PERSONID")
#SequenceGenerator(name="appUsersSeq", sequenceName="SEQ_PERSON", allocationSize=1)
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator = "appUsersSeq")
private long personid;
EjbService:
#Stateless
public class EjbService implements EjbServiceRemote {
#PersistenceContext(name = "Project1245")
private EntityManager em;
#Override
public void addTperson(Tperson tp) {
em.persist(tp);
}
}
0 is default value for long type. The id will be set after invoking select query for the related sequence, which commonly is executed when you persist the entity. Are you persisting the entity? In case yes, post the database sequence definition to check it.

Resources