I'm having issues trying to delete an entry in my database table.
The structure of the database is as follows:
User ---< UserET >--- ExitTicket
ExitTicket.java
#Entity
#Table(name = "exit_ticket")
public class ExitTicketEntry implements Serializable {
private static final long serialVersionUID = 1L;
private long id;
private String title;
private String dateET;
private Set<UserET> userETs= new HashSet<UserET>();
public ExitTicketEntry() {}
public ExitTicketEntry(String title,String dateET) {
this.title = title;
this.dateET = dateET;
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY )
#Column(name = "ticket_id")
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
#OneToMany(mappedBy = "exitTicketEntry", orphanRemoval=true)
public Set<UserET> getUserETs() {
return userETs;
}
public void setUserETs(Set<UserET> userETs) {
this.userETs = userETs;
}
public void addUserETs(UserET userETs) {
this.userETs.add(userETs);
}
//getters and setters
}
UserET.java
#Entity
#Table(name="userET")
public class UserET implements Serializable {
//private static final long serialVersionUID = 1L;
private long answerId;
private User user;
private ExitTicketEntry exitTicketEntry;
private String answer;
private Date dateAnswer;
#Id
#GeneratedValue
#Column(name="answerId")
public long getAnswerId() {
return answerId;
}
public void setAnswerId(long answerId) {
this.answerId = answerId;
}
#ManyToOne(cascade = CascadeType.ALL )
#JoinColumn(name = "user_id")
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "ticket_id")
public ExitTicketEntry getExitTicketEntry() {
return exitTicketEntry;
}
public void setExitTicketEntry(ExitTicketEntry exitTicketEntry) {
this.exitTicketEntry = exitTicketEntry;
}
#Column(name = "answer")
public String getAnswer(){
return answer;
}
public void setAnswer(String answer) {
this.answer = answer;
}
#Column(name = "dateAnswer")
#Temporal(TemporalType.DATE)
public Date getDateAnswer() {
return dateAnswer;
}
public void setDateAnswer(Date dateAnswer) {
this.dateAnswer = dateAnswer;
}
User.java
#Entity
#Table(name="USER")
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private long id;
private String user_name, user_password, user_type,user_realname;
private Set<UserET> userETs= new HashSet<UserET>();
public User() {
}
public User(String user_name,String user_password,String user_type,String user_realname) {
this.user_name = user_name;
this.user_password = user_password;
this.user_type = user_type;
this.user_realname=user_realname;
}
public void addExitTicketEntry(UserET group) {
this.userETs.add(group);
}
#Id
#GeneratedValue
#Column(name="user_id")
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
#OneToMany(mappedBy = "user", orphanRemoval=true)
public Set<UserET> getUserETs() {
return userETs;
}
public void setUserETs(Set<UserET> userETs) {
this.userETs = userETs;
}
public void addUserETs(UserET userETs) {
this.userETs.add(userETs);
} ... + getters and setters
I am able to insert a new Entry of ExitTicket correctly (using ExitTicketService.java), with this function:
public void addEntryET(ExitTicketEntry exitTicketEntry) {
log.info("adding entry in database");
try {
hibernateTemplate.save(exitTicketEntry);
}
catch(Exception e) {
log.info("error adding an entry in the database->"+e.toString());
}
}
However when I try to delete an entry from the database table, the hibernate delete only does 'select' commands and never gets to do a 'delete'
2018-11-05 09:28:27 INFO AuthService:72 - entro 1 ------
Hibernate: select exitticket0_.ticket_id as ticket_i1_0_0_, exitticket0_.dateET as dateET2_0_0_, exitticket0_.title as title3_0_0_ from exit_ticket exitticket0_ where exitticket0_.ticket_id=?
Mon Nov 05 09:28:27 CST 2018 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
2018-11-05 09:28:27 TRACE BasicBinder:65 - binding parameter [1] as [BIGINT] - [9]
2018-11-05 09:28:27 TRACE BasicExtractor:61 - extracted value ([dateET2_0_0_] : [VARCHAR]) - [2011-05-20]
2018-11-05 09:28:27 TRACE BasicExtractor:61 - extracted value ([title3_0_0_] : [VARCHAR]) - [test1]
2018-11-05 09:28:27 TRACE CollectionType:790 - Created collection wrapper: [com.jcg.spring.hibernate.pojo.ExitTicketEntry.userETs#9]
Hibernate: select userets0_.ticket_id as ticket_i4_2_0_, userets0_.answerId as answerId1_2_0_, userets0_.answerId as answerId1_2_1_, userets0_.answer as answer2_2_1_, userets0_.dateAnswer as dateAnsw3_2_1_, userets0_.ticket_id as ticket_i4_2_1_, userets0_.user_id as user_id5_2_1_, user1_.user_id as user_id1_1_2_, user1_.user_name as user_nam2_1_2_, user1_.user_password as user_pas3_1_2_, user1_.user_realname as user_rea4_1_2_, user1_.user_type as user_typ5_1_2_ from userET userets0_ left outer join USER user1_ on userets0_.user_id=user1_.user_id where userets0_.ticket_id=?
2018-11-05 09:28:27 TRACE BasicBinder:65 - binding parameter [1] as [BIGINT] - [9]
2018-11-05 09:28:27 INFO AuthService:99 - deleted entry with ID#=9
My delete function in my service class:
public void deleteById(Class<?> type, long id) {
log.info("entro 1 ------");
ExitTicketEntry e=(ExitTicketEntry) hibernateTemplate.load(type,id);
hibernateTemplate.delete(e);
}
I've been reading plenty of forums, but still have the same issue, I can't delete any entries. Am I missing something?
Related
I am trying to use JPA to fetch records from database. However I am able to insert records indatabse and even get all the records using createQuery method of class EntityManager.
But in below case I am not getting why the condition in where clause is not working.
Please help me figure it out.
POJO class :
#Entity
#Table(name = "frameworks_filter")
public class FilteredFrameworksDbStructure {
#Id
#Column(name="id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(name = "regular_name")
private String regularName;
#Column(name = "component_name")
private String componentName;
#Column(name = "component_owner")
private String componentOwner;
#Column(name = "frameworks")
private String frameworks;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getRegularName() {
return regularName;
}
public void setRegularName(String regularName) {
this.regularName = regularName;
}
public String getComponentName() {
return componentName;
}
public void setComponentName(String componentName) {
this.componentName = componentName;
}
public String getComponentOwner() {
return componentOwner;
}
public void setComponentOwner(String componentOwner) {
this.componentOwner = componentOwner;
}
public String getFrameworks() {
return frameworks;
}
public void setFrameworks(String frameworks) {
this.frameworks = frameworks;
}
}
DAO class method:
public List<FilteredFrameworksDbStructure> getFilteredFrameworks(String regularName) {
EntityManager entityManager = entityManagerFactory.createEntityManager();
List<FilteredFrameworksDbStructure> filteredFrameworksDbStructureList = entityManager
.createQuery("from FilteredFrameworksDbStructure F where F.regularName = :regular", FilteredFrameworksDbStructure.class)
.setParameter("regular", regularName)
.getResultList();
return filteredFrameworksDbStructureList;
}
Issue : Condition in where clause does not work. It simply fetch all the records irrespective of the regularName provided.
Regards,
Parag Vinchurkar
Why don't you use the JpaRepository or CrudRepository to fetch your results? Check out this tutorial here and here on how to use them.
And you can use your where clause. Please see below the example repository you can use to obtain the same results as the entityManager
public interface FilteredFrameworksDbStructureRepo extends JpaRepository<FilteredFrameworksDbStructure , Integer>{
List<FilteredFrameworksDbStructure> findAllByRegularName(String regularName)
}
Please note that you will have to change your id member variable from int to Integer
I have a model :
public class ABC implements Serializable {
private int baseId;
private Integer aId;
private Integer bId;
private Boolean isReal;
private TimeStamp updateTime;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name = "base_id", nullable = false)
public int getBaseId() {
return baseId;
}
public void setBaseId(int baseId) {
this.baseId = baseId;
}
#Basic
#Column(name = "a_id", nullable = false)
public Integer getAId() {
return aId;
}
public void setAId(Integer aId) {
this.aId = aId;
}
#Basic
#Column(name = "b_id", nullable = false)
public Integer getBId() {
return bId;
}
public void setBId(Integer bId) {
this.bId = bId;
}
#Basic
#Column(name = "is_real")
public Boolean getIsReal() {
return isReal;
}
public void setIsReal(Boolean isReal) {
this.isReal = isReal;
}
#Basic
#Column(name ="update_time")
public Timestamp getUpdateTime() {
return updateTime;
}
public void setUpdateTime(Timestamp updateTime) {
this.updateTime = updateTime;
}
}
I have a controller Class:
#RestController
#RequestMapping(path = "${serverconfig.api-base-path}/base")
public class BaseController {
/**
* Instance of an logger
*/
private static final Logger LOG =
LoggerFactory.getLogger(BaseController.class);
/**
* Base repository
*/
private BaseRepository baseRepository;
/***
*
* #param baseRepository
*/
public BaseController(BaseRepository baseRepository) {
LOG.trace("BaseRepository constructor method.");
this.baseRepository = baseRepository;
}
#PostMapping(path = Route.UPDATE_IS_REAL)
// #Transactional
public ABC updateIsReal(#Valid #RequestBody
#RequestParam("baseId") int baseId,
#RequestParam("isReal") boolean isReal){
ABC abc = baseRepository.findByBaseId(baseId);
Date date= new Date();
Timestamp ts = new Timestamp(date.getTime());
abc.setBaseId(baseId);
abc.setIsReal(isReal);
abc.setUpdateTime(ts);
return baseRepository.save(abc);
}
}
My repository class:
#Repository
public interface BaseRepository extends
JpaRepository<ABC, Integer> {
List<ABC> findByAId(Integer aId);
ABC findByBaseId(Integer baseId);
}
Database table has an entry :
"base_id": 1,
"a_Id": 1,
"b_Id": 1,
"is_real": null,
"update_time": null
When I call the endpoint it gives no error and returns:
"base_id": 1,
"aId": 1,
"bId": 1,
"isReal": yes,
"updateTime": 018-10-01T18:30:56.765+0000
But When I query the database, the record is not updated there. I am not understanding what I am doing wrong. I am supplying id when I try to make a rest call and that id exists in the database.
With save, changes won't necessary be flushed to DB immediately and might stay just in memory, until flush or commit commands are issued.
With saveAndFlush, changes will be flushed to DB immediately.
However, if you flush the changes in transaction and do not commit them, the changes still won't be visible to the outside transactions until the commit in this transaction.
In your BaseController try changing
return baseRepository.save(abc);
to
return baseRepository.saveAndFlush(abc);
Further information here and here
If someone was here for the same reason and didn't find an answer..:
Did you check if you have following set? Perhaps the whole schema may be getting re-created?
spring.jpa.hibernate.ddl-auto=create
I am using spring jpa repository with hibernate to save entites to my oracle database. How I can get the next value of my oracle database sequence using Spring-Hibernate?
This is my Event class :
#Entity
public class Event {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private Long seriesId;
private String description;
public Event() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getSeriesId() {
return seriesId;
}
public void setSeriesId(Long seriesId) {
this.seriesId = seriesId;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
I need to get the next value of the sequence once for the all event series in the event resolver.
public class EventResolver {
#Autowired
private EventRepository eventRepository;
public void createSeriesOfEvents(List<EventAPI> eventsToCreate){
Long seriesId = null; // TODO: Get the series id from database sequence
for (EventAPI currEvent : eventsToCreate){
Event newEvent = new Event();
newEvent.setDescription(currEvent.description);
newEvent.setSeriesId(seriesId);
eventRepository.save(newEvent);
}
}
}
Thanks for any kind of help..
Finally I Solved my problem in the Spring way, All you need is to add a native query in the JpaRepository like this:
public interface EventRepository extends JpaRepository<Event, Long> {
#Query(value = "SELECT seq_name.nextval FROM dual", nativeQuery =
true)
Long getNextSeriesId();
With Spring 5, you can use one of their built-in classes for this task like OracleSequenceMaxValueIncrementer
See all the available options in this package: https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/jdbc/support/incrementer/package-summary.html
Annotate your id property like so:
#Id
#GeneratedValue(generator = "idSequence")
#SequenceGenerator(schema = "MYORASCHEMA", name = "idSequence", sequenceName = "MY_ORACLE_SEQ_NAME", allocationSize = 1)
#Column(name="ID")
private Long id;
You can use this approach in JPA:
Query q = em.createNativeQuery("select seq_name.nextval from dual");
return (Long)q.getSingleResult();
I have some tables :
PROFIL : id_profil, ...
EXPERIENCE : id_experience, id_profil#, ...
COMPETENCE_LEVEL : id_competence_level, level, ...
One PROFIL can have lot of EXPERIENCE and lot of COMPETENCE_LEVEL.
One EXPERIENCE can have lot of COMPETENCE_LEVEL.
One COMPETENCE_LEVEL concerns lot of EXPERIENCE.
So, for me, between EXPERIENCE and COMPETENCE_LEVEL, this is a (n-p) ManyToMany relation.
I tried:
PROFIL.java:
#Entity
#Table(name="profil")
public class Profil {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="id_profil")
private Long idProfil;
public Profil() {
super();
}
public Long getIdProfil() {
return idProfil;
}
public void setIdProfil(Long idProfil) {
this.idProfil = idProfil;
}
#Override
public String toString() {
//[...]
}
}
EXPERIENCE.java:
#Entity
#Table(name="experience")
public class Experience {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="id_experience")
private Long idExperience;
#ManyToOne
#JoinColumn(name="id_profil")
private Profil idProfil;
private List<CompetenceLevel> competenceLevels;
public Experience() {
super();
idProfil = new Profil();
}
public Long getIdExperience() {
return idExperience;
}
public void setIdExperience(Long idExperience) {
this.idExperience = idExperience;
}
public Profil getIdProfil() {
return idProfil;
}
public void setIdProfil(Profil idProfil) {
this.idProfil = idProfil;
}
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(name = "experience_competence_level", joinColumns = #JoinColumn(name = "id_experience", referencedColumnName = "id_experience"), inverseJoinColumns = #JoinColumn(name = "id_competence_level", referencedColumnName = "id_competence_level"))
public List<CompetenceLevel> getCompetenceLevels() {
return competenceLevels;
}
public void setCompetenceLevels(List<CompetenceLevel> competenceLevels) {
this.competenceLevels = competenceLevels;
}
#Override
public String toString() {
// [...]
}
}
COMPETENCE_LEVEL.java:
#Entity
#Table(name="competence_level")
public class CompetenceLevel {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="id_competence_level")
private Long idCompetenceLevel;
#OneToOne
#JoinColumn(name="id_level")
private Level level;
#OneToOne
#JoinColumn(name="id_profil")
private Profil profil;
private List<Experience> experiences;
public CompetenceLevel() {
super();
}
public Long getIdCompetenceLevel() {
return idCompetenceLevel;
}
public void setIdCompetenceLevel(Long idCompetenceLevel) {
this.idCompetenceLevel = idCompetenceLevel;
}
public Level getLevel() {
return level;
}
public void setLevel(Level level) {
this.level = level;
}
public Profil getProfil() {
return profil;
}
public void setProfil(Profil profil) {
this.profil = profil;
}
#ManyToMany(mappedBy = "competenceLevels")
public List<Experience> getExperiences() {
return experiences;
}
public void setExperiences(List<Experience> experiences) {
this.experiences = experiences;
}
#Override
public String toString() {
// [...]
}
}
So, I have this error :
org.hibernate.MappingException: Could not determine type for: java.util.List, at table: competence_level, for columns: [org.hibernate.mapping.Column(experiences)]
I don't understand why. I follow this tuto : https://hellokoding.com/jpa-many-to-many-relationship-mapping-example-with-spring-boot-maven-and-mysql/
Do you have an idea ? Thanks.
The reason is simply: don't mix field and method annotations in the same persistent class.
Hibernate generates an unclear error here. It is very hard to figure out the reason of the error, if you don't face it before.
In your code, you are mixing field access and property access. See this answer.
I would prefer using only one of the possibilities. I use field annotations, like you did for idProfil.
In the book "Professional Java for Web Applications" by Nicholas S. Williams (very, very good) I found this:
You should never mix JPA property annotations and JPA field
annotations in the same entity. Doing so results in unspecified
behaviour and is very likely to cause errors.
And just for clearness, I wouldn't write this
#ManyToOne
#JoinColumn(name="id_profil")
private Profil idProfil;
// better:
// private Profil profil;
I have the next two entities
Person:
#Entity
#Table(name = "person")
public class PersonDTO implements Serializable {
private static final long serialVersionUID = -3859029259805663330L;
#Id
#Column(name = "person_id")
#SequenceGenerator(name = "PERSON_GENERATOR", sequenceName = "seq_person_id")
#GeneratedValue(generator = "PERSON_GENERATOR")
private Long personId;
#Column(name = "name")
private String name;
#OneToMany(fetch = FetchType.LAZY)
#JoinColumn(name = "person_id", updatable = false)
#Cascade(value = { CascadeType.ALL, CascadeType.DELETE_ORPHAN })
private List<PersonBookDTO> personBooks = new ArrayList<PersonBookDTO>();
public Long getPersonId() {
return personId;
}
public void setPersonId(final Long personId) {
this.personId = personId;
}
public String getName() {
return name;
}
public void setName(final String name) {
this.name = name;
}
public List<PersonBookDTO> getPersonBooks() {
return personBooks;
}
public void setPersonBooks(final List<PersonBookDTO> personBooks) {
this.personBooks = personBooks;
}
/**
* #see java.lang.Object#equals(Object)
*/
#Override
public boolean equals(final Object object) {
if (!(object instanceof PersonDTO)) {
return false;
}
PersonDTO rhs = (PersonDTO) object;
return new EqualsBuilder().appendSuper(super.equals(object))
.append(this.name, rhs.name).isEquals();
}
/**
* #see java.lang.Object#hashCode()
*/
#Override
public int hashCode() {
return new HashCodeBuilder(1636021877, -141724713)
.appendSuper(super.hashCode())
.append(this.name).toHashCode();
}
}
Person book:
#Entity
#Table(name = "person_book")
#NamedQueries({
#NamedQuery(name = "PersonBookDTO.getBooksByPersonIdList", query = "from PersonBookDTO s where s.person.personId in(:personIdList) and s.disabled=false")
})
public class PersonBookDTO implements Serializable {
private static final long serialVersionUID = -6382678873261874993L;
#Id
#Column(name = "person_book_id")
#SequenceGenerator(name = "PERSON_BOOK_GENERATOR", sequenceName = "seq_person_book_id")
#GeneratedValue(generator = "PERSON_BOOK_GENERATOR")
private Long personBookId;
#Column(name = "name")
private String name;
#Column(name = "disabled")
private boolean disabled;
#ManyToOne()
#JoinColumn(name = "person_id")
private PersonDTO person;
public Long getPersonBookId() {
return personBookId;
}
public void setPersonBookId(Long personBookId) {
this.personBookId = personBookId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isDisabled() {
return disabled;
}
public void setDisabled(boolean disabled) {
this.disabled = disabled;
}
public PersonDTO getPerson() {
return person;
}
public void setPerson(PersonDTO person) {
this.person = person;
}
/**
* #see java.lang.Object#equals(Object)
*/
public boolean equals(Object object) {
if (!(object instanceof PersonBookDTO)) {
return false;
}
PersonBookDTO rhs = (PersonBookDTO) object;
return new EqualsBuilder().appendSuper(super.equals(object)).append(this.disabled, rhs.disabled).append(this.personBookId, rhs.personBookId).append(this.name, rhs.name).append(this.person, rhs.person).isEquals();
}
/**
* #see java.lang.Object#hashCode()
*/
public int hashCode() {
return new HashCodeBuilder(213186089, -1592457573).appendSuper(super.hashCode()).append(this.disabled).append(this.personBookId).append(this.name).append(this.person).toHashCode();
}
}
I've enabled hibernate 2nd level cache for this entities:
<property name="hibernate.cache.use_second_level_cache">true</property>
<property name="hibernate.cache.provider_class">net.sf.ehcache.hibernate.EhCacheProvider</property>
<property name="net.sf.ehcache.configurationResourceName">/ehcache.xml</property>
...
<class-cache usage="read-write" class="com.test.dao.dto.PersonDTO"/>
<class-cache usage="read-write" class="com.test.dao.dto.PersonBookDTO"/>
Default cache from ehcache.xml:
<defaultCache
maxElementsInMemory="100000"
eternal="false"
timeToIdleSeconds="86400"
timeToLiveSeconds="86400"
overflowToDisk="false"
memoryStoreEvictionPolicy="LRU"
statistics="false"
>
Now I call the next test method in loop several times and in several threads:
(personIdList is a List and was filled previously)
txManager.startTransaction();
Query query = getSession().getNamedQuery("PersonBookDTO.getBooksByPersonIdList");
query.setParameterList("personIdList", personIdList);
List<PersonBookDTO> = query.list();
txManager.commitTransaction();
txManager.closeTransaction();
When I collected hibernate 2nd level cache statistis I've seen that only PersonDTO was taken from cache during the loop.
name: com.test.dao.dto.PersonDTO
count: 13
hit: 4
miss: 4
put: 13
size: 35389
and PersonBookDTO was only written
name: com.test.dao.dto.PersonBookDTO
count: 29
hit: 0
miss: 0
put: 29
size: 38194
I've enabled TRACE level for ehCache. Here's a part of log:
TRACE [ReadWriteCache] Caching: com.test.dao.dto.PersonBookDTO#8348946
TRACE [ReadWriteCache] Cached: com.test.dao.dto.PersonBookDTO#8348946
TRACE [ReadWriteCache] Cache hit: com.test.dao.dto.PersonDTO#70276
TRACE [ReadWriteCache] Cache hit: com.test.dao.dto.PersonDTO#79271
TRACE [ReadWriteCache] Caching: com.test.dao.dto.PersonBookDTO#8376615
TRACE [ReadWriteCache] Item was already cached: com.test.dao.dto.PersonBookDTO#8376615
TRACE [ReadWriteCache] Cache hit: com.test.dao.dto.PersonDTO#63179
TRACE [ReadWriteCache] Caching: com.test.dao.dto.PersonBookDTO#8315141
TRACE [ReadWriteCache] Item was already cached: com.test.dao.dto.PersonBookDTO#8315141
Maybe someone can explain this behavoir. Thanks!
UPDATE: this reproduces with all queries which returns Lists of DTOs. session.read(PersonBookDTO) reads from cache normally.
Results of explicit query are fetched from the second level cache only when query cache is turned on and enabled for that query (by setting appropriate query hints). So, if you want to cache results of the query, you need to enable query cache.
If you want to retrieve entity data from the second level cache, but don't want to retrieve query result as a whole from the query cache, you can run a query for ids and then fetch entities with those ids manually.