Hibernate - Redis: Second Level Cache is not working - java

I have an issue related to hibernate level 2 cache. It works with getById method, but not other method:
This is my code:
jpa:
database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
database: MYSQL
show-sql: true
properties:
hibernate.id.new_generator_mappings: true
hibernate.connection.provider_disables_autocommit: true
hibernate.cache.use_second_level_cache: true
hibernate.cache.use_query_cache: true
hibernate.cache.region.factory_class: com.mycompany.myapp.config.CustomRegionFactory
hibernate.generate_statistics: true
hibernate.cache.region_prefix: hibernate
hibernate.cache.use_structured_entries: true
#Configuration #EnableCaching public class CacheConfiguration {
#Bean
public javax.cache.configuration.Configuration<Object, Object> jcacheConfiguration(JHipsterProperties jHipsterProperties) {
MutableConfiguration<Object, Object> jcacheConfig = new MutableConfiguration<>();
Config config = new Config();
config.useSingleServer().setAddress(jHipsterProperties.getCache().getRedis().getServer());
jcacheConfig.setStatisticsEnabled(true);
jcacheConfig.setExpiryPolicyFactory(CreatedExpiryPolicy.factoryOf(new Duration(TimeUnit.SECONDS, jHipsterProperties.getCache().getRedis().getExpiration())));
return RedissonConfiguration.fromInstance(Redisson.create(config), jcacheConfig);
}
#Bean
public HibernatePropertiesCustomizer hibernatePropertiesCustomizer(javax.cache.CacheManager cm) {
return hibernateProperties -> hibernateProperties.put(ConfigSettings.CACHE_MANAGER, cm);
}
#Bean
public JCacheManagerCustomizer cacheManagerCustomizer(javax.cache.configuration.Configuration<Object, Object> jcacheConfiguration) {
return cm -> {
createCache(cm, com.mycompany.myapp.repository.UserRepository.USERS_BY_LOGIN_CACHE, jcacheConfiguration);
createCache(cm, com.mycompany.myapp.repository.UserRepository.USERS_BY_EMAIL_CACHE, jcacheConfiguration);
createCache(cm, com.mycompany.myapp.domain.User.class.getName(), jcacheConfiguration);
createCache(cm, com.mycompany.myapp.domain.Authority.class.getName(), jcacheConfiguration);
createCache(cm, com.mycompany.myapp.domain.User.class.getName() + ".authorities", jcacheConfiguration);
createCache(cm, com.mycompany.myapp.domain.Company.class.getName(), jcacheConfiguration);
// jhipster-needle-redis-add-entry
};
}
private void createCache(javax.cache.CacheManager cm, String cacheName, javax.cache.configuration.Configuration<Object, Object> jcacheConfiguration) {
javax.cache.Cache<Object, Object> cache = cm.getCache(cacheName);
if (cache != null) {
cm.destroyCache(cacheName);
}
cm.createCache(cacheName, jcacheConfiguration);
} }
public class CustomRegionFactory extends RedissonRegionFactory {
#Override
protected RedissonClient createRedissonClient(Map properties) {
Config config = new Config();
config.useSingleServer().setAddress("redis://127.0.0.1:6379").setRetryInterval(1500)
.setRetryAttempts(3).setConnectTimeout(10000)
.setClientName("client1");
return Redisson.create(config);
}
}
Entity:
package com.mycompany.myapp.domain;
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import javax.persistence.*;
import java.io.Serializable;
/**
* A Company.
*/
#Entity
#Table(name = "company")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Company implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "name")
private String name;
// jhipster-needle-entity-add-field - JHipster will add fields here, do not remove
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public Company name(String name) {
this.name = name;
return this;
}
public void setName(String name) {
this.name = name;
}
// jhipster-needle-entity-add-getters-setters - JHipster will add getters and setters here, do not remove
#Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof Company)) {
return false;
}
return id != null && id.equals(((Company) o).id);
}
#Override
public int hashCode() {
return 31;
}
#Override
public String toString() {
return "Company{" +
"id=" + getId() +
", name='" + getName() + "'" +
"}";
}
}
Please help me

Related

Jpa Specification Generic type class

I'm currently building a advance search for a project using Specifications and Criteria Builder, I have multiple entities that I would like to create a generic class Specification builder. My question, is it possible to do it?
Entity example
#Entity
#Table(name = "marcas")
public class Brand implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#Column(name = "nombre")
private String name;
#Enumerated(EnumType.STRING)
#Column(name = "tipo_marca")
private Brandtype brandtype;
#Column(name = "fecha_creacion")
private LocalDateTime creationDate;
#Column(name = "fecha_actalizacion")
private LocalDateTime updateDate;
#OneToMany(
mappedBy = "brand",
fetch = FetchType.LAZY
)
private Set<Bike> bikes;
#OneToMany(
mappedBy = "brand",
fetch = FetchType.LAZY
)
private Set<Model> models;
#OneToMany(
mappedBy = "brand",
fetch = FetchType.LAZY
)
private Set<Accesorie> accesories;
public Brand() {
}
public Brand(Integer id, String name, Brandtype brandtype) {
this.id = id;
this.name = name;
this.brandtype = brandtype;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Brandtype getBrandtype() {
return brandtype;
}
public void setBrandtype(Brandtype brandtype) {
this.brandtype = brandtype;
}
public Set<Bike> getBikes() {
return bikes;
}
public void setBikes(Set<Bike> bikes) {
this.bikes = bikes;
}
public Set<Model> getModels() {
return models;
}
public void setModels(Set<Model> models) {
this.models = models;
}
public Set<Accesorie> getAccesories() {
return accesories;
}
public void setAccesories(Set<Accesorie> accesories) {
this.accesories = accesories;
}
public LocalDateTime getCreationDate() {
return creationDate;
}
public void setCreationDate(LocalDateTime creationDate) {
this.creationDate = creationDate;
}
public LocalDateTime getUpdateDate() {
return updateDate;
}
public void setUpdateDate(LocalDateTime updateDate) {
this.updateDate = updateDate;
}
#PrePersist
public void beforeCreate(){
this.creationDate = LocalDateTime.now();
}
#PreUpdate
public void beforeUpdate(){
this.updateDate = LocalDateTime.now();
}
#Override
public String toString() {
return "Brand{" +
"id=" + id +
", name='" + name + '\'' +
", brandtype=" + brandtype+
'}';
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Brand brand = (Brand) o;
return id.equals(brand.id) && name.equals(brand.name);
}
#Override
public int hashCode() {
return Objects.hash(id, name);
}
}
Reposotory example
#Repository
public interface BrandRepository extends PagingAndSortingRepository <Brand, Integer>, JpaSpecificationExecutor<Brand> {
}
Search Criteria class:
public class SearchCriteria {
private String key;
private String operation;
private Object value;
public SearchCriteria() {
}
public SearchCriteria(String key, String operation, Object value) {
this.key = key;
this.operation = operation;
this.value = value;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getOperation() {
return operation;
}
public void setOperation(String operation) {
this.operation = operation;
}
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
}
And this is the class Specification:
public class BrandSpecification implements Specification<Brand>{
private SearchCriteria criteria;
public BrandSpecification(SearchCriteria searchCriteria) {
this.criteria = searchCriteria;
}
#Override
public Predicate toPredicate(Root<Brand> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
if (criteria.getOperation().equalsIgnoreCase(">")) {
return builder.greaterThanOrEqualTo(
root.<String> get(criteria.getKey()), criteria.getValue().toString());
}
else if (criteria.getOperation().equalsIgnoreCase("<")) {
return builder.lessThanOrEqualTo(
root.<String> get(criteria.getKey()), criteria.getValue().toString());
}
else if (criteria.getOperation().equalsIgnoreCase(":")) {
if (root.get(criteria.getKey()).getJavaType() == String.class) {
return builder.like(
root.<String>get(criteria.getKey()), "%" + criteria.getValue() + "%");
} else {
return builder.equal(root.get(criteria.getKey()), criteria.getValue());
}
}
return null;
}
public SearchCriteria getCriteria() {
return criteria;
}
public void setCriteria(SearchCriteria criteria) {
this.criteria = criteria;
}
}
I want to convert to generic so I can re use the code and dont need to rewrite it multiple times, can I have something like: public class GenericSpecification implements Specification<E>{}
You can do the following:
public class AppSpecification<T> implements Specification<T>{
private SearchCriteria criteria;
public AppSpecification(SearchCriteria searchCriteria) {
this.criteria = searchCriteria;
}
#Override
public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
if (criteria.getOperation().equalsIgnoreCase(">")) {
return builder.greaterThanOrEqualTo(
root.<T> get(criteria.getKey()), criteria.getValue().toString());
}
else if (criteria.getOperation().equalsIgnoreCase("<")) {
return builder.lessThanOrEqualTo(
root.<T> get(criteria.getKey()), criteria.getValue().toString());
}
else if (criteria.getOperation().equalsIgnoreCase(":")) {
if (root.get(criteria.getKey()).getJavaType() == String.class) {
return builder.like(
root.<T>get(criteria.getKey()), "%" + criteria.getValue() + "%");
} else {
return builder.equal(root.get(criteria.getKey()), criteria.getValue());
}
}
return null;
}
then you can initiate the class as follows:
var brandSpecification = new AppSpecification<Brand>(searchCriteria);

org.hibernate.MappingException: Unable to find column with logical name in Spring Hibernate

I am converting Hibernate project to Spring Hibernate Project. Since I'm integrating Hibernate with Spring, I am defining all the session factory, datasource definition in #Configuration. After deployment, when I start the server, I am getting below exception
Unable to find column with logical name: TEST_CODE in org.hibernate.mapping.Table(TEST_MONTHS) and its related supertables and secondary tables.
EntityClass:
#javax.persistence.Entity
#Table(name="TEST_MONTHS")
public class ConnectionMonth implements Serializable {
/**
* #generated
*/
private static final long serialVersionUID = -940496855L;
#Id
#Column(name = "TEST_CODE")
private String testCode;
#Id
#Column(name = "CONMONTH")
private String contractMonth;
#Column(name = "TYPE")
private String type;
#Column(name = "STARTDATE")
private Date startDate;
#Column(name = "ENDDATE")
private Date endDate;
public String gettestCode() {
return testCode;
}
public void settestCode(String testCode) {
this.testCode = testCode;
}
public String getContractMonth() {
return contractMonth;
}
public void setContractMonth(String contractMonth) {
this.contractMonth = contractMonth;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public Date getStartDate() {
return startDate;
}
public void setStartDate(Date startDate) {
this.startDate = startDate;
}
public Date getEndDate() {
return endDate;
}
public void setEndDate(Date endDate) {
this.endDate = endDate;
}
/**
* #generated
*/
#Override
public String toString() {
return "ContractMonth: " + contractMonth + " Type: " + type
+ " StartDate: " + startDate + " EndDate: " + endDate;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((testCode == null) ? 0 : testCode.hashCode());
result = prime * result
+ ((contractMonth == null) ? 0 : contractMonth.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ContractMonth other = (ContractMonth) obj;
if (testCode == null) {
if (other.testCode != null)
return false;
} else if (!testCode.equals(other.testCode))
return false;
if (contractMonth == null) {
if (other.contractMonth != null)
return false;
} else if (!contractMonth.equals(other.contractMonth))
return false;
return true;
}
}
Persistence Config:
#Configuration
#EnableTransactionManagement
#PropertySource({ "classpath:persistence.properties" })
#ComponentScan({ "com.test.commons.domain.*" })
public class PersistenceConfiguration {
#Autowired
private Environment env;
#Bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(restDataSource());
sessionFactory.setPackagesToScan(new String[] {
"com.test.commons.domain.employee"});
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
#Bean
public DataSource restDataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(env.getProperty("jdbc.driverClassName"));
dataSource.setUrl(env.getProperty("jdbc.url"));
dataSource.setUsername(env.getProperty("jdbc.user"));
dataSource.setPassword(env.getProperty("jdbc.pass"));
return dataSource;
}
#Bean
#Autowired
public HibernateTransactionManager transactionManager(
SessionFactory sessionFactory) {
HibernateTransactionManager txManager = new HibernateTransactionManager();
txManager.setSessionFactory(sessionFactory);
return txManager;
}
#Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
}
Properties hibernateProperties() {
return new Properties() {
{
setProperty("hibernate.hbm2ddl.auto",
env.getProperty("hibernate.hbm2ddl.auto"));
setProperty("hibernate.dialect",
env.getProperty("hibernate.dialect"));
setProperty("hibernate.globally_quoted_identifiers", "true");
}
};
}
}
persistence.properties:
# jdbc.X
jdbc.driverClassName=oracle.jdbc.driver.OracleDriver
jdbc.url=/*DB url*/
jdbc.user=pwd
jdbc.pass=pwd
# hibernate.X
hibernate.dialect=org.hibernate.dialect.OracleDialect
hibernate.show_sql=false
hibernate.hbm2ddl.auto=create-drop
Can you check table details in sql , is it having "" quotes around it or single quotes
As i also faced same issue in my code , in that i was having table details as below
CREATE TABLE `orders` (
`id` INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
`firstname` VARCHAR(50) NOT NULL,
);
And i was accessing it with below bean
#Entity
#Table(name="orders")
public class Order {
#Id
#GeneratedValue
#Column(name="id")
private int id;
#Column(name="firstname")
private String firstName;
#OneToMany(targetEntity=OrderLine.class,
cascade = CascadeType.ALL,
fetch = FetchType.LAZY)
#JoinTable(
name="orderlines",
joinColumns = {#JoinColumn(table = "orderlines", name="FK_orders_orders",
referencedColumnName = "order_id")},
inverseJoinColumns={#JoinColumn(table = "orders", name="FK_orders_orders",
referencedColumnName = "id")}
)
After removing single quotes it started working for me

failed to lazily initialize a collection of role ManyToMany relation

I have an entity question and an entity test with ManyToMany relationship between the two entitie.
when I want to view the questions of a test this error is occurred.
failed to lazily initialize a collection of role:
tn.esen.entities.Test.questions, could not initialize proxy - no Session
this is the JPA implementation of the two entities.
Question:
package tn.esen.entities;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import java.io.Serializable;
import java.util.Collection;
import java.util.Date;
#Entity
public class Question implements Serializable {
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((contenu == null) ? 0 :
contenu.hashCode());
result = prime * result + ((dateCreation == null) ? 0 :
dateCreation.hashCode());
result = prime * result + ((niveauDeDifficulte == null) ? 0 :
niveauDeDifficulte.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Question other = (Question) obj;
if (contenu == null) {
if (other.contenu != null)
return false;
} else if (!contenu.equals(other.contenu))
return false;
if (dateCreation == null) {
if (other.dateCreation != null)
return false;
} else if (!dateCreation.equals(other.dateCreation))
return false;
if (niveauDeDifficulte == null) {
if (other.niveauDeDifficulte != null)
return false;
} else if (!niveauDeDifficulte.equals(other.niveauDeDifficulte))
return false;
return true;
}
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="id_question")
private int id;
private String contenu;
private String niveauDeDifficulte;
private Date dateCreation;
#OneToMany(mappedBy="question",fetch = FetchType.EAGER)
private Collection <Reponse> reponses;
#ManyToOne
private Categorie categorie;
#ManyToOne
private Administrateur administrateur;
#ManyToMany(mappedBy = "questions",fetch = FetchType.EAGER)
private Collection<Test> tests;
public Question(){
super();
}
#Override
public String toString() {
return "Question [id=" + id + ", contenu=" + contenu + ",
niveauDeDifficulte=" + niveauDeDifficulte + "]";
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getContenu() {
return contenu;
}
public void setContenu(String contenu) {
this.contenu = contenu;
}
public String getNiveauDeDifficulte() {
return niveauDeDifficulte;
}
public void setNiveauDeDifficulte(String niveauDeDifficulte) {
this.niveauDeDifficulte = niveauDeDifficulte;
}
public Date getDateCreation() {
return dateCreation;
}
public void setDateCreation(Date dateCreation) {
this.dateCreation = dateCreation;
}
public Collection<Reponse> getReponses() {
return reponses;
}
public void setReponses(Collection<Reponse> reponses) {
this.reponses = reponses;
}
public Categorie getCategorie() {
return categorie;
}
public void setCategorie(Categorie categorie) {
this.categorie = categorie;
}
public Administrateur getAdministrateur() {
return administrateur;
}
public void setAdministrateur(Administrateur administrateur) {
this.administrateur = administrateur;
}
public Collection<Test> getTest() {
return tests;
}
public void setTest(Collection<Test> tests) {
this.tests = tests;
}
public Question(String contenu, String niveauDeDifficulte, Date
dateCreation) {
super();
this.contenu = contenu;
this.niveauDeDifficulte = niveauDeDifficulte;
this.dateCreation = dateCreation;
}
Test:
package tn.esen.entities;
#Entity
public class Test implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String duree;
private String typeDePreparation;
private String lieu;
private int nbrQuestionFacile;
private int nbrQuestionMoyen;
private int nbrQuestionDifficle;
#OneToMany(mappedBy = "test")
private Collection<Resultat> resultats;
#ManyToMany
private Collection<Question> questions;
#ManyToOne
private ResponsableTechnique responsableTechnique;
public Test() {
super();
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getDuree() {
return duree;
}
public void setDuree(String duree) {
this.duree = duree;
}
public Collection<Question> getQuestions() {
return questions;
}
public void setQuestions(Collection<Question> questions) {
this.questions = questions;
}
public Test(String duree, String typeDePreparation, String lieu, int
nbrQuestionFacile, int nbrQuestionMoyen,
int nbrQuestionDifficle) {
super();
this.duree = duree;
this.typeDePreparation = typeDePreparation;
this.lieu = lieu;
this.nbrQuestionFacile = nbrQuestionFacile;
this.nbrQuestionMoyen = nbrQuestionMoyen;
this.nbrQuestionDifficle = nbrQuestionDifficle;
}
public ResponsableTechnique getRésponsableTechnique() {
return responsableTechnique;
}
public void setRésponsableTechnique(ResponsableTechnique
résponsableTechnique) {
this.responsableTechnique = résponsableTechnique;
}
public String getTypeDePreparation() {
return typeDePreparation;
}
public void setTypeDePreparation(String typeDePreparation) {
this.typeDePreparation = typeDePreparation;
}
public String getLieu() {
return lieu;
}
public void setLieu(String lieu) {
this.lieu = lieu;
}
public int getNbrQuestionFacile() {
return nbrQuestionFacile;
}
public void setNbrQuestionFacile(int nbrQuestionFacile) {
this.nbrQuestionFacile = nbrQuestionFacile;
}
public int getNbrQuestionMoyen() {
return nbrQuestionMoyen;
}
public void setNbrQuestionMoyen(int nbrQuestionMoyen) {
this.nbrQuestionMoyen = nbrQuestionMoyen;
}
public int getNbrQuestionDifficle() {
return nbrQuestionDifficle;
}
public void setNbrQuestionDifficle(int nbrQuestionDifficle) {
this.nbrQuestionDifficle = nbrQuestionDifficle;
}
public Collection<Resultat> getResultats() {
return resultats;
}
public void setRésultats(Collection<Resultat> resultats) {
this.resultats = resultats;
}
}
}
When you get Test and access Test.questions later, after leaving the transaction, you will get a lazy initialization exception when the Test entity is detached and questions has not been initialized/fetched yet. You can either do a specific fetch, or depending on your configuration, you can call Test.getQuestions().size() before you exit the transaction.
References: How to solve lazy initialization exception using JPA and Hibernate as provider
LazyInitializationException in JPA and Hibernate
Hibernate LazyInitializationException using Spring CrudRepository

Display valid msg to user for org.hibernate.exception.ConstraintViolationException:

I m new to Springs, Hibernate and REST API.
How can i catch org.hibernate.exception.ConstraintViolationException ( I do not want to delete the mill data since you have dependent(child) data on the mill and display a appropriate msg to user that it cannot delete it due to orders exists for the mill.
Please Help.
Thank you
Here is my Code.
MillResource.java
#RequestMapping(value = "/mills/{id}",
method = RequestMethod.DELETE,
produces = MediaType.APPLICATION_JSON_VALUE)
#Timed
public ResponseEntity<Void> deleteMill(#PathVariable Long id) {
log.debug("REST request to delete Mill : {}", id);
millRepository.delete(id);
log.debug(" ", id);
return ResponseEntity.ok().headers(HeaderUtil.createEntityDeletionAlert("mill", id.toString())).build();
}
CrudRepository
void delete(ID id);
/**
* Deletes a given entity.
*
* #param entity
* #throws IllegalArgumentException in case the given entity is {#literal null}.
*/
HeaderUtil.java
public class HeaderUtil {
public static HttpHeaders createAlert(String message, String param) {
HttpHeaders headers = new HttpHeaders();
headers.add("X-omsApp-alert", message);
headers.add("X-omsApp-params", param);
return headers;
}
public static HttpHeaders createEntityCreationAlert(String entityName, String param) {
return createAlert("A new " + entityName + " is created with identifier " + param, param);
}
public static HttpHeaders createEntityUpdateAlert(String entityName, String param) {
return createAlert("A " + entityName + " is updated with identifier " + param, param);
}
public static HttpHeaders createEntityDeletionAlert(String entityName, String param) {
return createAlert("A " + entityName + " is deleted with identifier " + param, param);
}
public static HttpHeaders createFailureAlert(String entityName, String errorKey, String defaultMessage) {
HttpHeaders headers = new HttpHeaders();
headers.add("X-omsApp-error", defaultMessage);
headers.add("X-omsApp-params", entityName);
return headers;
}
}
Mill.java
import com.fasterxml.jackson.annotation.JsonIgnore;
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import javax.persistence.*;
import javax.validation.constraints.*;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.Objects;
/**
* A Mill.
*/
#Entity
#Table(name = "mill")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Mill implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#NotNull
#Size(max = 10)
#Column(name = "code", length = 10, nullable = false)
private String code;
#NotNull
#Column(name = "name", nullable = false)
private String name;
#OneToOne
private Addresses addresses;
#OneToOne
private NoteSet notes;
#OneToMany(mappedBy = "mill")
#JsonIgnore
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private Set<Price> pricess = new HashSet<>();
#OneToMany(mappedBy = "mill")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private List<Quality> qualitiess = new ArrayList<>();
#OneToMany(mappedBy = "mill")
#JsonIgnore
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private Set<SimpleGsmShade> simpleGsmShadess = new HashSet<>();
#OneToMany(mappedBy = "mill")
#JsonIgnore
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private Set<CustomerGroup> groupss = new HashSet<>();
#OneToMany(mappedBy = "mill")
#JsonIgnore
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private Set<DerivedGsmShade> derivedGsmShadess = new HashSet<>();
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Addresses getAddresses() {
return addresses;
}
public void setAddresses(Addresses addresses) {
this.addresses = addresses;
}
public NoteSet getNotes() {
return notes;
}
public void setNotes(NoteSet noteSet) {
this.notes = noteSet;
}
public Set<Price> getPricess() {
return pricess;
}
public void setPricess(Set<Price> prices) {
this.pricess = prices;
}
public List<Quality> getQualitiess() {
return qualitiess;
}
public void setQualitiess(List<Quality> qualitys) {
this.qualitiess = qualitys;
}
public Set<SimpleGsmShade> getSimpleGsmShadess() {
return simpleGsmShadess;
}
public void setSimpleGsmShadess(Set<SimpleGsmShade> simpleGsmShades) {
this.simpleGsmShadess = simpleGsmShades;
}
public Set<CustomerGroup> getGroupss() {
return groupss;
}
public void setGroupss(Set<CustomerGroup> customerGroups) {
this.groupss = customerGroups;
}
public Set<DerivedGsmShade> getDerivedGsmShadess() {
return derivedGsmShadess;
}
public void setDerivedGsmShadess(Set<DerivedGsmShade> derivedGsmShades) {
this.derivedGsmShadess = derivedGsmShades;
}
#Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Mill mill = (Mill) o;
if(mill.id == null || id == null) {
return false;
}
return Objects.equals(id, mill.id);
}
#Override
public int hashCode() {
return Objects.hashCode(id);
}
#Override
public String toString() {
return "Mill{" +
"id=" + id +
", code='" + code + "'" +
", name='" + name + "'" +
'}';
}
}
Basically you have to handle the Exception. Introduce a try catch block and output the appropriate message.
Handle the exception at the base level and funnel it to the controller.

SPRING JPA - org.hibernate.PersistentObjectException: detached entity passed to persist:

I've been stuck here for almost a week trying find the answer on the internet but sadly nothing worked. :( Everytime I try to update using this method:
private Tenant updateTenantWithApplicationProperties(List<TenantApplicationProperty> newTenantApplicationProperties, String tenantId) {
String reason = "Update application properties.";
Tenant existingTenant = tenantRepository.findById(tenantId);
List<TenantApplicationProperty> temp = existingTenant.getTenantApplicationProperties();
existingTenant.setTenantApplicationProperties(newTenantApplicationProperties);
setApplicationPropertiesUpdateValues(temp, existingTenant);
if(newTenantApplicationProperties != null && newTenantApplicationProperties.size() != 0) {
Tenant savedTenantWithAppProps = saveTenantWithLog(existingTenant, reason);
return savedTenantWithAppProps;
}
return existingTenant;
}
Im always getting this error:
javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: com.infor.ecom.tenant.manager.model.entity.ApplicationProperty
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1361)
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1289)
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1295)
at org.hibernate.ejb.AbstractEntityManagerImpl.merge(AbstractEntityManagerImpl.java:876)
But when Im using this method it works fine:
public Tenant updateTenant(Tenant tenant) {
List<Database> databases = tenant.getDatabases();
List<Administrator> administrators = tenant.getAdministrators();
validateUpdateTenant(tenant);
validateDatabases(databases);
validateAdministrators(administrators);
Tenant existingTenant = findByIdWithAllDetails(tenant.getId());
List<Database> listExistingDatabases = existingTenant.getDatabases();
Database existingEcomDb = getDatabaseByType(listExistingDatabases,
TenantManagerConstants.ECOM_DATASOURCE);
setDatabaseUpdateValues(listExistingDatabases, tenant);
setAdministratorsUpdateValues(existingTenant.getAdministrators(),
tenant);
setProductUpdateValue(existingTenant.getProduct(), tenant);
setApplicationPropertiesUpdateValues(existingTenant.getTenantApplicationProperties(), tenant);
setEcomDBParamsDefaultValues(tenant);
setAdministratorDefaultValues(tenant);
Database updateEcomDb = getDatabaseByType(tenant.getDatabases(),
TenantManagerConstants.ECOM_DATASOURCE);
Boolean shouldInstallNewDB = true;
if (existingEcomDb.getName().equalsIgnoreCase(updateEcomDb.getName())
&& existingEcomDb.getHost().equalsIgnoreCase(
updateEcomDb.getHost())
&& existingEcomDb.getPort().equals(updateEcomDb.getPort())) {
shouldInstallNewDB = false;
} else {
testEcomDBConnection(updateEcomDb);
}
int ecomDbTableCount = getEcomDBTableCount(updateEcomDb);
String[][] languages = formatAndValidateLanguages(updateEcomDb
.getEcomDatabaseParameters().getLanguages());
Tenant updatedTenant = saveExistingTenant(tenant);
if (updatedTenant != null) {
if (shouldInstallNewDB || ecomDbTableCount == 0) {
installDatabase(updateEcomDb, languages, updatedTenant);
} else {
updateDatabase(updateEcomDb, languages, updatedTenant);
}
storageService.updateTenantFolderStructure(updatedTenant);
} else {
throw new TenantManagerException(
ApiMessageConstants.M_TENANT_PROVISION_ERROR,
ApiMessageConstants.C_TENANT_PROVISION_ERROR);
}
return updatedTenant;
}
So here is my complete codes:
Tenant.java
package com.infor.ecom.tenant.manager.model.entity;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.xml.bind.annotation.XmlRootElement;
import com.infor.ecom.tenant.manager.constant.TenantManagerConstants;
import com.infor.ecom.tenant.manager.constant.TenantStatusEnum;
#Entity
#Table(name="tenant")
#XmlRootElement(name = "Tenant",namespace = "http://com.infor.ecom.tenant.manager/Tenant")
public class Tenant extends BaseModel {
private static final long serialVersionUID = -6687293822212120396L;
#Id
private String id;
private String displayName;
private String description;
private String url;
private String apiKey;
private String status;
#OneToMany(mappedBy = "tenant", fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
private List<Database> databases;
#OneToMany(mappedBy = "tenant", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private List<Activity> activites;
#OneToMany(mappedBy = "tenant", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private List<Administrator> administrators;
private String message;
#OneToMany(mappedBy = "tenant", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private List<TenantApplicationProperty> tenantApplicationProperties;
#OneToOne(mappedBy = "tenant", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
private Product product;
public Database findEcomDatabase() {
Database database = null;
if(databases != null) {
for(Database db : databases) {
if(db.getDatasource() != null) {
if(TenantManagerConstants.ECOM_DATASOURCE.equals(db.getDatasource().getName())) {
database = db;
break;
}
}
}
}
return database;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getDisplayName() {
return displayName;
}
public void setDisplayName(String displayName) {
this.displayName = displayName;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getApiKey() {
return apiKey;
}
public void setApiKey(String apiKey) {
this.apiKey = apiKey;
}
public String getStatus() {
return status;
}
public void setStatus(TenantStatusEnum statusEnum) {
this.status = statusEnum.name();
}
public List<Database> getDatabases() {
return databases;
}
public void setDatabases(List<Database> databases) {
this.databases = databases;
}
public void addDatabase(Database database) {
if (this.databases == null) {
this.databases = new ArrayList<Database>();
}
database.setTenant(this);
this.databases.add(database);
}
public List<Activity> getActivites() {
return activites;
}
public void setActivites(List<Activity> activities) {
this.activites = activities;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public void setStatus(String status) {
this.status = status;
}
public List<Administrator> getAdministrators() {
return this.administrators;
}
public void setAdministrators(List<Administrator> administrators) {
for (Administrator admin:administrators) {
admin.setTenant(this);
}
this.administrators = administrators;
}
public void addAdministrator(Administrator administrator) {
if (this.administrators == null) {
this.administrators = new ArrayList<Administrator>();
}
administrator.setTenant(this);
this.administrators.add(administrator);
}
public List<TenantApplicationProperty> getTenantApplicationProperties() {
return tenantApplicationProperties;
}
public void setTenantApplicationProperties(
List<TenantApplicationProperty> tenantApplicationProperties) {
this.tenantApplicationProperties = tenantApplicationProperties;
}
public void addTenantApplicationProperty(TenantApplicationProperty tenantApplicationProperty) {
if (this.tenantApplicationProperties == null) {
this.tenantApplicationProperties = new ArrayList<TenantApplicationProperty>();
}
tenantApplicationProperty.setTenant(this);
this.tenantApplicationProperties.add(tenantApplicationProperty);
}
public Product getProduct() {
return product;
}
public void setProduct(Product product) {
product.setTenant(this);
this.product = product;
}
}
TenantApplicationProperty.java
package com.infor.ecom.tenant.manager.model.entity;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import com.infor.ecom.tenant.manager.model.entity.pk.TenantApplicationPropertyPK;
#Entity
#Table(name = "tenant_application_property")
#IdClass(TenantApplicationPropertyPK.class)
public class TenantApplicationProperty extends BaseModel {
private static final long serialVersionUID = 1L;
#Id
#ManyToOne
#JoinColumn(name = "tenant_id")
private Tenant tenant;
#Id
#OneToOne
#JoinColumn(name = "application_property_id")
private ApplicationProperty applicationProperty;
private String value;
public TenantApplicationProperty() {
super();
}
/**
* Added constructor to handle custom query for
* findByTenantIdApplicationPropertyName. No need to retrieve Tenant and
* ApplicationProperty
*
* #param value
*/
public TenantApplicationProperty(String value) {
setTenant(null);
setApplicationProperty(null);
setValue(value);
}
public Tenant getTenant() {
return tenant;
}
public void setTenant(Tenant tenant) {
this.tenant = tenant;
}
public ApplicationProperty getApplicationProperty() {
return applicationProperty;
}
public void setApplicationProperty(ApplicationProperty applicationProperty) {
this.applicationProperty = applicationProperty;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime
* result
+ ((applicationProperty == null) ? 0 : applicationProperty
.hashCode());
return result;
}
#Override
public boolean equals(Object object) {
if (this == object)
return true;
if (object == null)
return false;
if (getClass() != object.getClass())
return false;
TenantApplicationProperty tenantAppProp = (TenantApplicationProperty) object;
if (applicationProperty == null) {
if (tenantAppProp.applicationProperty != null) {
return false;
}
} else if (!applicationProperty.getApplicationPropertyGroup().getName().equals(tenantAppProp.applicationProperty.getApplicationPropertyGroup().getName())
|| !applicationProperty.getName().equals(tenantAppProp.applicationProperty.getName())) {
return false;
}
return true;
}
}
TenanatApplicationPropertyPK.java
package com.infor.ecom.tenant.manager.model.entity.pk;
public class TenantApplicationPropertyPK implements java.io.Serializable {
private static final long serialVersionUID = 1L;
private String tenant;
private Integer applicationProperty;
public String getTenantId() {
return tenant;
}
public void setTenantId(String tenant) {
this.tenant = tenant;
}
public Integer getApplicationPropertyId() {
return applicationProperty;
}
public void setApplicationPropertyId(Integer applicationProperty) {
this.applicationProperty = applicationProperty;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime
* result
+ ((applicationProperty == null) ? 0 : applicationProperty
.hashCode());
result = prime * result + ((tenant == null) ? 0 : tenant.hashCode());
return result;
}
#Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
TenantApplicationPropertyPK tenantAppPropPK = (TenantApplicationPropertyPK) obj;
if (applicationProperty == null) {
if (tenantAppPropPK.applicationProperty != null) {
return false;
}
} else if (!applicationProperty
.equals(tenantAppPropPK.applicationProperty)) {
return false;
}
if (tenant == null) {
if (tenantAppPropPK.tenant != null) {
return false;
}
} else if (!tenant.equals(tenantAppPropPK.tenant)) {
return false;
}
return true;
}
}
ApplicationProperty.java
package com.infor.ecom.tenant.manager.model.entity;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.Table;
#Entity
#Table(name = "application_property")
public class ApplicationProperty extends BaseModel {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
private String defaultValue;
private boolean isVisible;
private boolean clientVisible;
#OneToOne
#JoinColumn(name = "property_group_id")
private ApplicationPropertyGroup applicationPropertyGroup;
#OneToOne
#JoinColumn(name = "property_type_id")
private ApplicationPropertyType applicationPropertyType;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDefaultValue() {
return defaultValue;
}
public void setDefaultValue(String defaultValue) {
this.defaultValue = defaultValue;
}
public boolean getIsVisible() {
return isVisible;
}
public void setIsVisible(boolean isVisible) {
this.isVisible = isVisible;
}
public boolean getClientVisible() {
return clientVisible;
}
public void setClientVisible(boolean clientVisible) {
this.clientVisible = clientVisible;
}
public ApplicationPropertyGroup getApplicationPropertyGroup() {
return applicationPropertyGroup;
}
public void setApplicationPropertyGroup(ApplicationPropertyGroup applicationPropertyGroup) {
this.applicationPropertyGroup = applicationPropertyGroup;
}
public ApplicationPropertyType getApplicationPropertyType() {
return applicationPropertyType;
}
public void setApplicationPropertyType(ApplicationPropertyType applicationPropertyType) {
this.applicationPropertyType = applicationPropertyType;
}
}
ApplicationPropertyGroup.java
package com.infor.ecom.tenant.manager.model.entity;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Table(name = "application_property_group")
public class ApplicationPropertyGroup extends BaseModel {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
ApplicationPropertyType.java
package com.infor.ecom.tenant.manager.model.entity;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Table(name = "application_property_type")
public class ApplicationPropertyType extends BaseModel {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
TenantServiceImpl.java
private Tenant updateTenantWithApplicationProperties(List<TenantApplicationProperty> newTenantApplicationProperties, String tenantId) {
String reason = "Update application properties.";
Tenant existingTenant = tenantRepository.findById(tenantId);
List<TenantApplicationProperty> temp = existingTenant.getTenantApplicationProperties();
existingTenant.setTenantApplicationProperties(newTenantApplicationProperties);
setApplicationPropertiesUpdateValues(temp, existingTenant);
if(newTenantApplicationProperties != null && newTenantApplicationProperties.size() != 0) {
Tenant savedTenantWithAppProps = saveTenantWithLog(existingTenant, reason);
return savedTenantWithAppProps;
}
return existingTenant;
}
private Tenant saveTenantWithLog(Tenant tenant, String reason) {
Tenant updatedTenant = tenantRepository.save(tenant);
TenantLog tenantLog = new TenantLog();
tenantLog.setTenantId(updatedTenant.getId());
tenantLog.setDisplayName(updatedTenant.getDisplayName());
tenantLog.setDescription(updatedTenant.getDescription());
tenantLog.setUrl(updatedTenant.getUrl());
tenantLog.setApiKey(updatedTenant.getApiKey());
tenantLog.setStatus(TenantStatusEnum.valueOf(updatedTenant.getStatus()));
tenantLog.setReason(reason);
tenantLog.setMessage(updatedTenant.getMessage());
tenantLogRepository.save(tenantLog);
return updatedTenant;
}
private void setApplicationPropertiesUpdateValues(List<TenantApplicationProperty> existingTenantAppProps, Tenant tenant) {
List<TenantApplicationProperty> newTenantApplicationProperties = (tenant.getTenantApplicationProperties() != null) ? tenant.getTenantApplicationProperties() : new ArrayList<TenantApplicationProperty>();
if(newTenantApplicationProperties.size() != 0) {
for(TenantApplicationProperty tenantAppProp : newTenantApplicationProperties) {
int index = existingTenantAppProps.indexOf(tenantAppProp);
if (index < 0) {
// throw an error -- tenantAppProp should always exist, right?
} else {
existingTenantAppProps.get(index).setValue(tenantAppProp.getValue());
}
}
tenant.setTenantApplicationProperties(existingTenantAppProps);
}
}
public Tenant updateTenant(Tenant tenant) {
List<Database> databases = tenant.getDatabases();
List<Administrator> administrators = tenant.getAdministrators();
validateUpdateTenant(tenant);
validateDatabases(databases);
validateAdministrators(administrators);
Tenant existingTenant = findByIdWithAllDetails(tenant.getId());
List<Database> listExistingDatabases = existingTenant.getDatabases();
Database existingEcomDb = getDatabaseByType(listExistingDatabases,
TenantManagerConstants.ECOM_DATASOURCE);
setDatabaseUpdateValues(listExistingDatabases, tenant);
setAdministratorsUpdateValues(existingTenant.getAdministrators(),
tenant);
setProductUpdateValue(existingTenant.getProduct(), tenant);
setApplicationPropertiesUpdateValues(existingTenant.getTenantApplicationProperties(), tenant);
setEcomDBParamsDefaultValues(tenant);
setAdministratorDefaultValues(tenant);
Database updateEcomDb = getDatabaseByType(tenant.getDatabases(),
TenantManagerConstants.ECOM_DATASOURCE);
Boolean shouldInstallNewDB = true;
if (existingEcomDb.getName().equalsIgnoreCase(updateEcomDb.getName())
&& existingEcomDb.getHost().equalsIgnoreCase(
updateEcomDb.getHost())
&& existingEcomDb.getPort().equals(updateEcomDb.getPort())) {
shouldInstallNewDB = false;
} else {
testEcomDBConnection(updateEcomDb);
}
int ecomDbTableCount = getEcomDBTableCount(updateEcomDb);
String[][] languages = formatAndValidateLanguages(updateEcomDb
.getEcomDatabaseParameters().getLanguages());
Tenant updatedTenant = saveExistingTenant(tenant);
if (updatedTenant != null) {
if (shouldInstallNewDB || ecomDbTableCount == 0) {
installDatabase(updateEcomDb, languages, updatedTenant);
} else {
updateDatabase(updateEcomDb, languages, updatedTenant);
}
storageService.updateTenantFolderStructure(updatedTenant);
} else {
throw new TenantManagerException(
ApiMessageConstants.M_TENANT_PROVISION_ERROR,
ApiMessageConstants.C_TENANT_PROVISION_ERROR);
}
return updatedTenant;
}
private Tenant saveExistingTenant(Tenant tenant) {
tenant.setStatus(TenantStatusEnum.INPROGRESS);
tenant.setMessage(ApiMessageConstants.M_DATABASE_UPDATE_INPROGRESS);
String reason = ApiMessageConstants.R_UPDATE_TENANT;
return saveTenantWithLog(tenant, reason);
}
In application property, you defined 1-1 relation like:
#OneToOne
#JoinColumn(name = "property_group_id")
private ApplicationPropertyGroup applicationPropertyGroup;
#OneToOne
#JoinColumn(name = "property_type_id")
private ApplicationPropertyType applicationPropertyType;
While you have not defined the same relation (note it should work bidirectionally i.e. say for e.g. if you as a person related to an employee id, then employee id is related to you as a person well) in individual property ApplicationPropertyGroup and ApplicationPropertyType.
You should add the same 1-1 relation in ApplicationPropertyGroup and ApplicationPropertyType with ApplicationProperty.

Categories

Resources