Map/Access entities with composite key - java

In my application I have 3 core classes as described below.
public class Semana {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Integer series;
private String observacao;
private Integer ordenacao;
#OneToMany(mappedBy = "semana")
#JsonBackReference
#OrderBy("ordenacao asc ")
private List<TreinoOrdenado> treinoOrdenados;
}
public class TreinoOrdenado {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne
#JoinColumn(name = "id_semana")
private Semana semana;
#ManyToOne
#JoinColumn(name = "id_treino")
private Treino treino; // can be repeated in the database but with different "ordenacao"
private Integer ordenacao;
}
#Table(name = "exercicio_ordenado")
public class ExercicioOrdenado {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne
#JoinColumn(name = "id_treino")
#JsonBackReference
#ToString.Exclude
private Treino treino;
#ManyToOne
#JoinColumn(name = "id_exercicio")
private Exercicio exercicio;
private Integer ordenacao;
#ManyToOne
#JoinTable(name = "parametro")
private Parametro parametro;
}
And this Parametro class which is a relationship between those 3 classes.
public class Parametro {
#EmbeddedId
private ParametroId parametroId = new ParametroId();
#MapsId("semana")
#OneToOne
#JoinColumn(name = "semana_id")
private Semana semana;
#MapsId("treino")
#OneToOne
#JoinColumn(name = "treino_id")
private TreinoOrdenado treino;
#MapsId("exercicio")
#OneToOne
#JoinColumn(name = "exercicio_id")
private ExercicioOrdenado exercicio;
private Integer series;
private String repeticoes;
private String observacao;
}
public class ParametroId implements Serializable {
#Column(name = "semana_id")
private Long semana;
#Column(name = "treino_id")
private Long treino;
#Column(name = "exercicio_id")
private Long exercicio;
}
So, here is my problem. I want to be able to access the Parametro from it's parent class ExercicioOrdenado, but in order to be distinguishable in the database the class Parametro needs the reference from the other two (Semana, TreinoOrdenado).
With my current mapping I got this error:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource
[org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Invocation of init method failed; nested exception is org.hibernate.MappingException: Foreign key (FK73ewcy2r50kw71o4he51dkolv:parametro
[parametro_exercicio_id,parametro_semana_id,parametro_treino_id])) must have same number of columns as the referenced primary key (parametro [id])
I can persist paremetros in the database with:
parametros.setSemana(semana);
parametros.setExercicio(exercicioOrdenado);
parametros.setTreino(treinoOrdenado);
parametroRepository.save(parametros);
But I can't retrieve from ExercicioOrdenado with the mapping.
I don't know the right approach to do this.

I think i now a way...
To do this we can use #Embeddable and #EmbeddedId annotation.
In this link have exemples.
https://www.baeldung.com/jpa-composite-primary-keys
#Entity
public class Parametro {
#EmbeddedId
private ParametroId parametroId;
#OneToOne
#JoinColumn(name = "exercicio_id")
#ForeignKey(name = "fk_exercicio_id")
private ExercicioOrdenado exercicio;
#OneToOne
#JoinColumn(name = "semana_id")
#ForeignKey(name = "fk_semana_id")
private Semana semana;
#OneToOne
#JoinColumn(name = "treino_id")
#ForeignKey(name = "fk_treino_id")
private TreinoOrdenado treino;
private Integer series;
private String repeticoes;
private String observacao;
}
#Embeddable
public class ParametroId {
private log id;
private log semana;
private log treino;
private log exercicio;
}
I believe that this is the way to create a personalized primary key using jpa. I have not tested the relationships of entities in the primary key. I know that there is more than one form to do that.
JPA #OneToOne with Shared ID -- Can I do this Better?

Related

HQL query doesn't order by other mapped entity criteria

I have the following entities in a Hibernate - Spring proyect.
Member:
#Entity
#Table(name = "member")
public class Member implements Serializable {
private static final long serialVersionUID = 1871629487715861212L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(name = "first_name")
private String firstName;
#Column(name = "last_name")
private String lastName;
#Column(name = "ident_doc")
private String identDoc;
#Column(name = "join_date")
private String joinDate;
private String nickname;
#OneToOne(mappedBy = "member")
private MemberContact memberContact;
#OneToMany(mappedBy = "member", cascade = CascadeType.ALL)
private List<MemberChapterLog> memberChapterLogs;
#OneToMany(mappedBy = "member")
private List<ChapterOfficers> chapterOfficers;
#OneToOne(mappedBy = "contactMember", cascade = CascadeType.ALL)
private Chapter asChapterContact;
Chapter:
#Entity
#Table(name = "chapter")
#NamedQuery(
name = "Chapter_Get_Detailed_Members_List",
query = "from MemberChapterLog where chapter.id = :paramChapter and active = true "+
"order by member.lastName asc")
public class Chapter implements Serializable {
private static final long serialVersionUID = -8387387246818721664L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String initials;
#Column(name ="chap_name")
private String chapName;
#ManyToOne
#JoinColumn(name = "category")
private ChapCategory category;
#OneToOne
#JoinColumn(name = "contact_member")
private Member contactMember;
#OneToOne(mappedBy = "chapter", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private ChapterContact chapterContact;
#OneToMany(mappedBy = "chapter")
private List<MemberChapterLog> memberChapterlogs;
#OneToMany(mappedBy = "chapter")
private List<ChapterOfficers> chapterOfficers;
MemberChapterLog:
#Entity
#Table(name = "member_chapter_log")
public class MemberChapterLog implements Serializable {
private static final long serialVersionUID = -643503606583240644L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "member_id")
private Member member;
#ManyToOne
#JoinColumn(name = "chapter_id")
private Chapter chapter;
#Column(name = "log_date")
private String logDate;
private String comment;
private boolean active;
I want to get a list of the active members of certain chapter (passed as ':paramChapter'), order by their last name. When I run the named query at chapter ("from MemberChapterLog where chapter.id = :paramChapter and active = true order by member.lastName asc") it generates the following error:
org.hibernate.HibernateException: Errors in named queries:
Chapter_Get_Detailed_Members_List failed because of: org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected token: member near line 1, column 105 [from dev.xarlsr.cdt.entity.MemberChapterLog where chapter.id = :paramChapter and active = true order by member.lastName asc]
If I delete the order by member.lastName it works properly (without any order, byt the way).
I tried to change the mapping by changing the tables foreign keys and the ownership, but doesn't work. I tried to change the fetch type without results. What am I doing wrong?
The problem is the mapping:
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "member_id")
private Member member;
member is a keyword in JPQL/HQL and soft-keyword handling was only introduced in Hibernate 6, so you will need to change the name of the field to e.g. memberAssociation and the query condition to ... order by memberAssociation.lastName asc

Hibernate Self reference

I'm trying to map with Hibernate an entity Product with self reference to other products.
The JSON sent to create a project is like this:
{"name":"chair", "description":"red chair",
"parent": {"name":"table","description":"red table"}
}
When I receive this json, I need to persist on DB the child product and set PARENT_PRODUCT_ID with the productId from parent attribute.
Some help, please?
public class Product implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "ID")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer productId;
#Column(name = "NAME")
private String name;
#Column(name = "DESCRIPTION")
private String description;
#OneToMany(cascade=CascadeType.ALL)
#JoinColumn(name="PRODUCT_ID")
private List<Image> images;
#OneToMany(cascade=CascadeType.ALL)
#JoinColumn(name="PRODUCT_ID")
private List<Product> children;
#ManyToOne
#JoinColumn(name = "PARENT_PRODUCT_ID")
private Product parent;
Image.java:
#Entity
#Table
public class Image implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "ID")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer imageId;
#Column(name = "TYPE")
private String type;
#ManyToOne
#JoinColumn(name = "PRODUCT_ID", nullable = false)
private Product product;
In the oneToMany relationships, I think it should be like:
#OneToMany(cascade=CascadeType.ALL, mappedBy="parent")
private List<Product> children;

Unable to find column with logical name hibernate

I have table where to 2 columns join another relations. I was tried join this with #JoinColumns but i getting error Invocation of init method failed; nested exception is org.hibernate.MappingException: Unable to find column with logical name CLASS_ID in table item_sub_class
I looked in h2-console and in table item_sub_class i see column class_id. Look screenshot
This is my relations code from Item class
#Entity
#JsonIgnoreProperties(ignoreUnknown = true)
public class Item implements Serializable {
#Id
private Long id;
private String description;
private String name;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "class_id")
private ItemClass itemClass;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumns({
#JoinColumn(name= "subclass_id",referencedColumnName = "subclass"),
#JoinColumn(name= "class_id",referencedColumnName = "class_id")
})
private ItemSubClass itemSubClass;
private Long sellPrice;
//getter and setters
}
And ItemSubClass
#Entity
public class ItemSubClass implements Serializable {
#Id
#GeneratedValue
private Long id;
#JsonProperty("subclass")
#Column(name = "subclass")
private Long subclass;
private String name;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "class_id")
private ItemClass itemClass;
//getters and setters
}
Some one can explain what is bad and why this relation throwing me error? This is possible to fix this?

how to resolve the 'save transient instance before saving' error on one to many relationship in hibernate jpa

this is the parent entity this is the child entityi have tried the suggested solution to similar error above but my application still spits out the same exception. please i need help
below is the exception
org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing: com.domkat.springmvcjpa.model.Cpfaceleft1angle.cpftid -> com.domkat.springmvcjpa.model.Fromtocp
at org.hibernate.engine.spi.CascadingAction$8.noCascade(CascadingAction.java:380)
at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:177)
at org.hibernate.event.internal.AbstractFlushingEventListener.cascadeOnFlush(AbstractFlushingEventListener.java:162)
at org.hibernate.event.internal.AbstractFlushingEventListener.prepareEntityFlushes(AbstractFlushingEventListener.java:153)
at org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:89)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1234)
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:404)
at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.beforeTransactionCommit(JdbcTransaction.java:101)
at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:175)
at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:75)
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:515)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:757)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:726)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:478)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:272)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
at com.sun.proxy.$Proxy626.save(Unknown Source)
#Entity
#Table(name = "cpobservedhorizontalangles")
public class Cpobservedhorizontalangles implements Serializable {
private static final long serialVersionUID = 1L;
#Column(name = "degree")
private Integer degree;
#Column(name = "minute")
private Integer minute;
#Column(name = "second")
private Integer second;
#Column(name = "degminsec")
private String degminsec;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "ohaid")
private Integer ohaid;
#OneToMany(cascade={CascadeType.ALL},mappedBy = "ohaid")
private List<Cpfaceleft2angle> cpfaceleft2angleList;
#OneToMany(cascade={CascadeType.ALL},mappedBy = "ohaid")
private List<Cpfaceright2angle> cpfaceright2angleList;
#OneToMany(cascade={CascadeType.ALL},mappedBy = "ohaid")
private List<Cpfaceleft1angle> cpfaceleft1angleList;
#OneToMany(cascade={CascadeType.ALL},mappedBy = "ohaid")
private List<Cpfaceright1angle> cpfaceright1angleList;
...getters and setters... this is the child entity
#Entity
#Table(name = "cpfaceleft1angle")
public class Cpfaceleft1angle implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "id")
private Integer id;
#OneToMany(cascade={CascadeType.PERSIST},mappedBy = "cpfl1id")
private List<Fromtocp> fromtocpList;
#JoinColumn(name = "ohaid", referencedColumnName = "ohaid")
#ManyToOne
private Cpobservedhorizontalangles ohaid;
#JoinColumn(name = "faceid", referencedColumnName = "faceid")
#ManyToOne
private Faceleft faceid;
...getters and setters... this is the parent class but it contains other
entities
public class Fromtocp implements Serializable {
private static final long serialVersionUID = 1L;
// #Max(value=?) #Min(value=?)//if you know range of your decimal fields consider using these annotations to enforce field validation
#Column(name = "distance")
private Double distance;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "ftcpid")
private Integer ftcpid;
#Column(name = "diffleft")
private String diffleft;
#Column(name = "diffright")
private String diffright;
#Column(name = "meandiff")
private String meandiff;
#Column(name = "oadegdec")
private Double oadegdec;
#Column(name = "fb")
private Double fb;
#Column(name = "bb")
private Double bb;
#JoinColumn(name = "fromcp", referencedColumnName = "cpid")
#ManyToOne
private Controlpoints fromcp;
#JoinColumn(name = "cpfl1id", referencedColumnName = "id")
#ManyToOne
private Cpfaceleft1angle cpfl1id;
#JoinColumn(name = "cpfl2id", referencedColumnName = "id")
#ManyToOne
private Cpfaceleft2angle cpfl2id;
#JoinColumn(name = "cpfr1id", referencedColumnName = "id")
#ManyToOne
private Cpfaceright1angle cpfr1id;
#JoinColumn(name = "cpfr2id", referencedColumnName = "id")
#ManyToOne
private Cpfaceright2angle cpfr2id;
#JoinColumn(name = "tocp", referencedColumnName = "cpid")
#ManyToOne
private Controlpoints tocp;
...this is the other entity the parent class contains.
#Controller
public class SurveyController {
#Autowired
private SurveyService ss;
#Autowired
private ControlPointService cps;
#Autowired
private ScpService sps;
#Autowired
private CpobservedhorizontalanglesService cpos;
#Autowired
private Cpfaceleft1angleService cpfl1;
#Autowired
private Cpfaceleft2angleService cpfl2;
#Autowired
private Cpfaceright1angleService cpfr1;
#Autowired
private Cpfaceright2angleService cpfr2;
#Autowired
private FromTocpService ftcps;
#Autowired
private FaceleftService fls;
#Autowired
private FacerightService frs;
private Processor processor = new Processor();
HttpSession session;
#RequestMapping(value = "/surveydetails")
public String showSurveyDetailsPage(Model model) {
Surveys survey = new Surveys();
model.addAttribute("survey", survey);
return "SurveyDetails";
}
#RequestMapping(value = "/stations", method = RequestMethod.POST)
public String createSurvey(#RequestParam("surveyTitle") String title,
#RequestParam("cp1Label") String cp1Label, #RequestParam("cp1Northings") double northingsCp1,
#RequestParam("cp1Eastings") double eastingsCp1, #RequestParam("cp2Label") String cp2Label,
#RequestParam("cp2Northings") double northingsCp2, #RequestParam("cp2Eastings") double eastingsCp2,
#RequestParam("distance") double distance, #RequestParam("fl1Deg") int fl1Deg,
#RequestParam("fl1Min") int fl1Min, #RequestParam("fl1Sec") int fl1Sec,
#RequestParam("fl2Deg") int fl2Deg, #RequestParam("fl2Min") int fl2Min, #RequestParam("fl2Sec") int fl2Sec,
#RequestParam("fr1Deg") int fr1Deg, #RequestParam("fr1Min") int fr1Min, #RequestParam("fr1Sec") int fr1Sec,
#RequestParam("fr2Deg") int fr2Deg, #RequestParam("fr2Min") int fr2Min, #RequestParam("fr2Sec") int fr2Sec) {
Surveys survey = new Surveys();
Scp scp = new Scp();
Signups su = null;
Cpobservedhorizontalangles o1 = new Cpobservedhorizontalangles();
o1.setDegree(fl1Deg);
o1.setMinute(fl1Min);
o1.setSecond(fl1Sec);
o1.setDegminsec(processor.degToString(fl1Deg, fl1Min, fl1Sec));
Cpfaceleft1angle fl1 = new Cpfaceleft1angle();
fl1.setOhaid(o1);
fl1.setFaceid(faceleft1);
cpos.save(o1);
cpfl1.save(fl1);
please help. thanks
i have resolved the problem. And in addition i found out how i can actually save just the parent class by calling the save method on the parent and then it saves the child entities as well. jpa makes it quite easy.
i will use an illustration of employee and address. lets say an employee can have more than one address it means we will have two tables in the database and two entity classes, one for each of these tables right?. it also means that the employee table becomes the parent table while the address becomes the child table right? the code below just shows how you can save the parent class and by the saving the parent class the child entities get saved as well! all you do is set the parent object(in this case the employee) on the child object(in this case the address), then set the List(the list of child in this case is address. so it becomes List) on the parent entity. then call the save method on the parent.
...necessary imports...
#Entity
#Table(name = "address")
#NamedQueries({
#NamedQuery(name = "Address.findAll", query = "SELECT a FROM Address a")})
public class Address implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "address_id")
private Integer addressId;
#Column(name = "employee_address")
private String employeeAddress;
#JoinColumn(name = "employee_id", referencedColumnName = "employee_id")
#ManyToOne
private Employee employeeId;
public Address() {
}
...getters and setters for this entity...
#Entity
#Table(name = "employee")
#NamedQueries({
#NamedQuery(name = "Employee.findAll", query = "SELECT e FROM Employee e")})
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "employee_id")
private Integer employeeId;
#Column(name = "name")
private String name;
#Column(name = "email")
private String email;
#Column(name = "phone")
private String phone;
#OneToMany(cascade=CascadeType.ALL,mappedBy = "employeeId")
private List<Address> addressList;
public Employee() {
}
...getters and setters for this class...
...below is the class that makes use of the entities...
public class SaveExample {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("JPAJoinTableTutorialsPU");
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
Employee employee = new Employee();// employee object
Address address = new Address(); // Address Object
address.setEmployeeAddress("set the value");
address.setEmployeeId(employee);
List<Address>addressList=new ArrayList<>();
addressList.add(address);
employee.setEmail("set the value");
employee.setName("set the value for name");
employee.setPhone("set the value");
employee.setAddressList(addressList);
em.persist(employee);
em.getTransaction().commit();
}
}
i hope that helps some people..thanks

Entity without Primary Key ID

Hi I want to create an Entity which doesn't have an ID.
#Entity
#Table(name="USER_PROD_LIC_TYPE_ALL")
public class UserProdLicTypeAll {
#EmbeddedId
private UserProdLicTypeAllPK id;
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="USER_ID")
private User user;
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="LICENSE_TYPE_ID")
private LicenseType licType;
....
}
since it doesn't have primary key i created Embeddable class as below:
#Embeddable
public class UserProdLicTypeAllPK {
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="USER_ID")
private User user;
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="LICENSE_TYPE_ID")
private LicenseType licType;
...
}
The combination of these two fields returns a unique value.
But it doesn't work. I get
org.springframework.beans.factory.UnsatisfiedDependencyException: exception.
Do i need to have references in User and LicenseType entities for both UserProdLicTypeAll and UserProdLicTypeAllPK? I have tried that also but still it doesn't work.
This is my private hell. I'm not sure what the best way to solve it properly.
My best solution is:
#Entity
#Table(name = TableName.AREA_USER)
#IdClass(UserAreaPK.class)
public class UserArea implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = UserAreaPK.C_AREA_ID)
private Long areaId;
#Id
#Column(name = UserAreaPK.C_USER_ID)
private String userId;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = UserAreaPK.C_AREA_ID, insertable = false, updatable = false)
private Area area;
And
/**
* Primary key for the relationship User-Area
*/
public class UserAreaPK implements Serializable {
protected static final String C_AREA_ID = "area_id";
protected static final String C_USER_ID = "user_id";
private static final long serialVersionUID = 1L;
#Id
#Column(name = C_AREA_ID)
private Long areaId;
#Id
#Column(name = C_USER_ID)
private String userId;

Categories