Hi I have a confusing error with my Spring-boot-JPA-Hibernate classes.
I used the JPA Dali tools to create the Entity classes from my SQL Schema.
While using them (with Spring-boot-jpa / hibarnate) I have some strange problems with unmatched queries.
Here is one example:
Properties:
hibernate.dialect=org.hibernate.dialect.MySQLDialect
spring.jpa.hibernate.ddl-auto=none
spring.datasource.url=jdbc:mysql://localhost:3306/users
spring.datasource.username=root
spring.datasource.password=root
Entity:
#Entity
#Table(name="n_user")
#NamedQuery(name="NUser.findAll", query="SELECT n FROM NUser n")
public class NUser implements Serializable {
private static final long serialVersionUID = 1L;
#Id
private int id;
private String imageUrl1;
private String name_first;
public NCaterer() {
}
public int getId() {
return this.id;
}
public void setId(int id) {
this.id = id;
}
public String getImageUrl1() {
return this.imageUrl1;
}
public void setImageUrl1(String imageUrl1) {
this.imageUrl1 = imageUrl1;
}
public String getName_first() {
return this.name_first;
}
public void setName_first(String name_first) {
this.name_first = name_first;
}
}
Repository:
public interface UserRepo extends CrudRepository<NUser, Long> {
}
But Hibernate creates this query of it:
Hibernate:
/* select
generatedAlias0
from
NUser as generatedAlias0 */ select
nuser0_.id as id1_0_,
nuser0_.image_url1 as image_ur2_0_,
nuser0_.name_first as name_firs3_0_
from
n_user nuser0_
The Problem here is the image_url1 it should be imageurl1 as described in the Entity class. This happens on several points.
Why do Hibernate transform CamelCase getters into camel_case in the query? And how can I config it not to do it?
If you want to specify column name by your own use #Column annotation for your fields.
Example:
#Column(name = "imageUrl1")
private String imageUrl1;
#Column(name = "nameFirst")
private String name_first;
It seems there have been many people experiencing the same problem in different circumstances. Maybe go and have a look at the different naming strategies below:
Naming Strategy One
Naming Strategy Two
Naming Strategy Three
You can however change the configuration of your hibernation. Have a look here for further help with regards to that. Or, go and have a look at this post and see how someone changed it using the above methods.
I went to the documentation (http://docs.jboss.org/envers/docs/#revisionlog) there it was written that if we annonate an entity with #RevisionEntity then Hibernate will not create default revinfo table by its own instead it will map the entity which is annotated with #RevisionEntity. I tried still its createing default table named as revinfo and not custom named table as RevisionTable.
Following is the code :
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import org.hibernate.envers.RevisionEntity;
import org.hibernate.envers.RevisionNumber;
import org.hibernate.envers.RevisionTimestamp;
#RevisionEntity
public class RevisionTable {
#Id
#GeneratedValue
#RevisionNumber
private int id;
#RevisionTimestamp
private long timestamp;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public long getTimestamp() {
return timestamp;
}
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}
}
I am not understanding where i am going wrong. As i am new to Hibernate Envers, it will be helpfull if explain the solution in detail.
Your revision entity needs to also contain these annotations:
#Entity
#Table(name="REVISIONS_TABLE_NAME")
and it needs to be scanned by hibernate like any other entity. Please refer to the documentation, this was specified there: http://docs.jboss.org/envers/docs/
I'm getting the following error:
Could not determine type for: java.util.Set, at table: Ruleset, for columns: [org.hibernate.mapping.Column(ruleset)]
class snippet:
#Entity
public class Ruleset implements java.io.Serializable {
#Id
#OneToOne(targetEntity = RulesetStatus.class)
private Integer id;
private Set<Rule> ruleset = new HashSet<Rule>(0);
public Ruleset() {
}
public Ruleset(Integer ID, Set<Rule> ruleset) {
this.id = ID;
this.ruleset = ruleset;
}
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
public Set<Rule> getRuleSet(){
return this.ruleset;
}
public void setRuleset(Set<Rule> ruleset) {
this.ruleset = ruleset;
}
}
I've figured out that annotating ruleset as Transient makes the problem go away, but then ruleset won't be persisted to the DB. How do I tell hibernate about the type of this field?
I'm very new to Hibernate so I'm totally lost here.
__________________________Edit__________________________
The actual relationship should have been #ManyToMany as a rule can be in many rulesets and a ruleset can have many rules.
I added the #ManyToMany annotation to the set, then did not have a corresponding set in the Rule Class to map to. I added the set in the rule class, added the #ManyToMany annotation to that, and no I have no errors.
Does this seem correct?
By default, all fields (or properties) are mapped in JPA. That's why you have to tell the JPA provider what your Set is supposed to map (one-to-many, many-to-many, #ElementCollection, etc.), or map it as #Transient to tell the provider that you don't want the property to be persisted.
If we make a column Id which corresponds to id of User, then why don't we put it near the variable id instead of the getter for id ? I got the answer to that here - Where to put hibernate annotations?.
But, because my book put it near the getter, it looks like some class will need to access this object via getter to serialize/persist it to a database. What is this class and how is does it perform the persistence ? Do I call its methods to do the persistence ?
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
#Entity
public class User {
private Long id;
private String password;
#Id
#GeneratedValue
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
Hibernate will use reflection to find the appropriate methods or fields on your class to read. This is why Hibernate is able to read private fields.
The code that does this reflection is called from session.save(Object object).
I still learning about Ebean ORM with Play Framework. have problem with unexpected evolution script that generated by Play!Framework. I'm using Play!Framework 2.1.1 with JDK 1.7 update 5 64-bit. Sorry, for long code snippet in this question.
I have two Ebean Model looks like following:
Course.java
package models;
import play.data.validation.Constraints;
import play.db.ebean.Model;
import javax.persistence.*;
#Entity
#Table(name = "castillo_courses")
public class Course extends Model {
public enum CourseType {
COMPULSORY(1), BASIC_INTEREST(2), ADVANCED_INTEREST(3), THESIS(4);
private int value;
CourseType(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
#Id
private String code;
#Constraints.Required
private String course_name;
#Constraints.Required
private String credits;
#Constraints.Required
private CourseType course_type;
// Ebean finder and Other getter and setter method
......
}
CourseInterest.java
package models;
import play.data.validation.Constraints;
import play.db.ebean.Model;
import javax.persistence.*;
#Entity
#Table(name = "castillo_course_interest")
public class CourseInterest extends Model {
public enum InterestType {
ARCHITECTURAL_INFRA(1), SOFTWARE_TECH(2), INFORMATION_PROCESSING(3), ENTERPRISE_SYSTEM(4), COMP_INTELLIGENCE(5);
private int value;
InterestType(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
#Id
#ManyToOne
#JoinColumn(name = "course_code", referencedColumnName = "code")
private Course course;
#Id
#Constraints.Required
private InterestType interest_type;
// Ebean finder and Other getter and setter method
......
}
This is generated evolution script from the models above:
# --- Created by Ebean DDL
# To stop Ebean DDL generation, remove this comment and start using Evolutions
# --- !Ups
create table castillo_courses (
code varchar(255) not null,
course_name varchar(255),
credits varchar(255),
course_type integer,
constraint ck_castillo_courses_course_type check (course_type in (0,1,2,3)),
constraint pk_castillo_courses primary key (code))
;
create table castillo_course_interest (
course_name varchar(255),
credits varchar(255),
course_type integer,
interest_type integer not null,
constraint ck_castillo_course_interest_course_type check (course_type in (0,1,2,3)),
constraint ck_castillo_course_interest_interest_type check (interest_type in (0,1,2,3,4)))
;
create sequence castillo_courses_seq;
create sequence castillo_course_interest_seq;
# ..... !DOWNS code not shown
What I expected with the generated evolution script is:
In castillo_courses CREATE TABLE script, ck_castillo_courses_course_type constraint should check in (1,2,3,4) as defined by CourseType.value attribute, not to check in (0,1,2,3). I suspect evolution generated this check by using ORDINAL value of my Enums.
In castillo_course_interest CREATE TABLE script, it define again all castillo_courses fields except code. I expect the script is only define course_code column as defined by #JoinColumn annotation. There is another problem here. It has no script to generate primary key constraint too, because I have defined two #Id defined in model.
I appreciate to anyone that can explain, give advice, or help me with this problem.. :)
Kindly regards.
user the #EnumValue("1")
sample.
If all the values are parsable as Integers then Ebean will persist and fetch them as integers rather than strings.
public enum InterestType {
#EnumValue("1")
ARCHITECTURAL_INFRA(1),
#EnumValue("2")
SOFTWARE_TECH(2),
#EnumValue("3")
INFORMATION_PROCESSING(3),
#EnumValue("4")
ENTERPRISE_SYSTEM(4),
#EnumValue("5")
COMP_INTELLIGENCE(5);
private int value;
InterestType(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
For question number 1, I used suggestion from #publiclass1.
For question number 2, I learn about Compound Primary Key. On CourseInterest model, I used the Compound Primary Key because I want it to have 2 type of primary key, one is the foreign key (course_code) and the other is a common field (interest_type). So, I tried like following.
This is sample of CourseInterest model :
#EmbeddedId // using compound primarykey
public CourseInterestPK key;
#MapsId("courseCode") // map embedded key
#ManyToOne
#JoinColumn(name = "course_code", referencedColumnName = "code")
public Course course;
#MapsId("interestType") // map embedded key
#Constraints.Required
public InterestType interest_type;
This is sample of CourseInterestPK (Compound Primary Key definition) class:
#Embeddable
public class CourseInterest15541120PK {
#Column(name = "course_code")
public String courseCode;
#Column(name = "interest_type")
public CourseInterest.InterestType interestType;
#Override
public boolean equals(Object obj) {
... // MUST to override this method
}
#Override
public int hashCode() {
... // MUST to override this method
}
}
So, with these technique, I get the evolution script that I want to. ;)