I have three tables
CREATE TABLE "ingredient" (
"id" INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 1, INCREMENT BY 1) PRIMARY KEY,
"ingredient" VARCHAR(50) NOT NULL
);
CREATE TABLE "pizza" (
"id" INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 1, INCREMENT BY 1) PRIMARY KEY,
"pizza" VARCHAR(50) NOT NULL
);
CREATE TABLE "pizza_structure" (
"pizza_id" INT NOT NULL,
"ingredient_id" INT NOT NULL,
"amount" INT NOT NULL
);
how to join them, to get Pizzas structure as a Map
#Entity
#Table(name = "ingredient")
public class Ingredient{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
public Ingredient() {
}
}
#Entity
#Table(name = "pizza")
public class Pizza {
#Id
#GeneratedValue
private Long id;
private String name;
#OneToMany ????
private Map<Ingredient, Integer> pizzaStructure;
public Pizza() {
}
public Pizza(String name, Map<Long, Integer> pizzaStructure) {
this.name = name;
this.pizzaStructure = pizzaStructure;
}
}
do I need to create #Embeddable class PizzaStructure, if yes when how to use it?
now I'm getting an error
Invocation of init method failed; nested exception is org.hibernate.AnnotationException: Use of #OneToMany or #ManyToMany targeting an unmapped class:
how to join them, to get Pizzas structure as a Map
It seems to look like this:
#ElementCollection
#CollectionTable(name = "pizza_structure", joinColumns = {#JoinColumn(name = "pizza_id")})
#Column(name = "amount")
#MapKeyJoinColumn(name = "ingredient_id")
private Map<Ingredient, Integer> pizzaStructure;
do I need to create #Embeddable class PizzaStructure
No.
More info is here: Hibernate User Guide - Maps.
Note that table pizza_structure should have foreign keys to pizza and ingredient tables and also unique constrain of pizza_id and ingredient_id, like this (it's postgresql dialect):
create table pizza_structure
(
pizza_id ... constraint fk_structure_pizza references pizza,
ingredient_id ... constraint fk_structure_ingredient references ingredient,
amount ...,
constraint pizza_structure_pkey primary key (pizza_id, ingredient_id)
);
You have a manyToMany relationship between pizza and ingredient and an additional column in your relationship.
I found a similar question here: JPA 2.0 many-to-many with extra column
(I would comment, but i do not have enough reputation.)
Related
In the database there is a table having a reflexive one-to-many relationship :
create table structure
(
struct_code varchar2(15) not null,
str_struct_code varchar2(15),
struct_lib varchar2(255),
struct_sigle varchar2(10),
struct_comment clob,
struct_interne smallint default 1,
constraint pk_structure primary key (struct_code)
);
alter table structure add constraint fk_structur_associati_structur foreign key (str_struct_code) references structure (struct_code);
I created the corresponding model :
#Entity
#Table(name = "structure")
public class Structure {
#Id()
#Column(name="struct_code")
private String code;
#Column(name="struct_sigle")
private String sigle;
#Column(name="struct_lib")
private String lib;
#Column(name="struct_interne")
private Integer interne;
#ManyToOne
#JoinColumn(name = "struct_code")
private Structure sousStructure;
public Structure() {
super();
}
public Structure(String code) {
super();
}
// getters and setters
}
But when I built the project then I got the error : mappingexception repeated column in mapping for entity : com.ambre.pta.model.Structure column: struct_code (should be mapped with insert="false" update="false")
So how to write correctly the reflexive relation ?
I do have something like this in place:
#ManyToOne
#JoinColumn(name = "parent_struct_code", nullable = true)
private Structure parentStructure;
#OneToMany(mappedBy = "parentStructure", cascade = CascadeType.REMOVE, fetch=FetchType.LAZY)
private List<Structure> sousStructures = new ArrayList<>();
I'm new with JPA, and want to create a Database with this relation :
|Participant|
|id : INT (PK) | id_event : INT (PK, FK) |
|Event|
|id : INT (PK) |
I'm totally lost and barely figure the syntax of the examples I found :/
But I understood I need to create an other class to contain the two pieces of the PK, which leads to another question : can this class be an inner-class (for optimisation purposes) ?
I hope I'm not asking too much but I really want to get it.
Your entities might be like this:
#Entity
public class Participant {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToMany(fetch = FetchType.LAZY) // or any other relation
private List<Event> events;
// fields, constructors, getters, setters
}
#Entity
public class Event {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
// fields, constructors, getters, setters
}
In this case JPA will create 3 tables with the following queries (SQL dialect will vary from DB to DB, in this case I used H2 database):
CREATE TABLE Event (
id bigint GENERATED BY DEFAULT AS IDENTITY,
PRIMARY KEY (id)
);
CREATE TABLE Participant (
id bigint GENERATED BY DEFAULT AS IDENTITY,
PRIMARY KEY (id)
);
CREATE TABLE Participant_Event (
Participant_id bigint NOT NULL,
events_id bigint NOT NULL
)
Participant_Event is automatically created join table to link participants and events.
Here is a good example of understanding JPA entity relations.
For a OneToMany relation you need the below entities and tables:
Participant
Event
The Event entity is simple:
#Entity
public class Event {
#Id
private Long id;
// fields, constructors, getters, setters
}
The entity Participant has to hold the composite key (aka two pieces of the PK), so, every Participant is only linked once with an Event.
#Entity
public class Participant {
#EmbeddedId
private EventParticipantPK id;
#OneToMany(fetch = FetchType.LAZY)
private List<Event> events;
// fields, constructors, getters, setters
}
The composite key is declared as an EmbeddedId.
The EventParticipantPK should be like:
#Embeddable
public class EventParticipantPK {
#Column (name = "PARTICIPANT_ID")
private Long participantId;
#Column (name = "EVENT_ID")
private Long eventId;
// fields, constructors, getters, setters
}
I hope this helps.
It`s possible to create one map with hibernate #ManyToOne just like this:
public class IndicadorAtos {
#JsonIgnore
#Id
#Column(name="cod_ato_praticado")
private Integer codAtoPraticado;
#Column(name="descricao_ato")
private String ato;
#JoinColumn(name = "cod_ato", referencedColumnName = "cod_ato")
#ManyToOne
#Fetch(FetchMode.SUBSELECT)
private Atos atos;
}
But in some cases I dont have association or in my table IndicadorAtos have one code, that don`t existis in table Atos
this is my tables:
create table IndicadorAtos (
codAtoPraticado integer primary key,
ato varchar(250),
cod_ato integer
);
create table Atos(
cod_ato integer primary key.
name varchar(250)
)
I try to create this join:
Select t FROM IndicadorAtos t , Atos a where t.cod_ato = a.cod_ato, but I need to return all records from my IndicadorAtos, and with this select he only return all itens that have one item in Atos.
tks
It`s possible to create one map with hibernate #ManyToOne
Yes; it is called unidirectional relationship.
If I understood your question properly, you want to select all entries from IndicadorAtos with possibly associated entries from Atos. You can achieve this by using left join as follows:
SELECT t FROM IndicadorAtos t LEFT JOIN t.atos at
provided that you have an entity Atos defined like:
#Entity
public class Atos {
#Id #GeneratedValue
private int cod_ato;
private String name;
// getters and setters
}
Given these two tables:
CREATE TABLE `soc` (
`id` INT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(32),
PRIMARY KEY (`id`));
CREATE TABLE `soc_attitude` (
`soc_id` INT NOT NULL,
`target_soc_id` INT NOT NULL,
`attitude` INT,
PRIMARY KEY (`soc_id`,`target_soc_id`));
In the Soc class, I want to get all rows matching this.soc_id from the soc_attitude table using a field like this:
private Map<Integer,Integer> attitudes;
Where the key of the map is target_soc_id and the value is attitude.
I got as far as this:
#Entity
#Table(name = "soc")
public class Soc {
#Id
#Column( name="id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#Column(name="name")
private String name;
#ElementCollection
#CollectionTable(name="soc_attitude",joinColumns=#JoinColumn(name="soc_id"))
#Column(name="attitude")
private Map<Integer,Integer> attitudes;
But I think this will make soc_id the key and attitude the value.
What annotations do I use? (using Hibernate 4.3.11.Final)
Use #MapKeyColumn
Try this:
#ElementCollection
#CollectionTable(name="soc_attitude",joinColumns=#JoinColumn(name="soc_id"))
#Column(name="attitude")
#MapKeyColumn(name="target_soc_id")
private Map<Integer,Integer> attitudes;
I have a problem very similar to this: How do I join tables on non-primary key columns in secondary tables?
But I'm not sure if I can apply the same solution.
I have two tables like these:
CREATE TABLE CUSTOMER
(
CUSTOMER_ID INTEGER NOT NULL,
DETAIL_ID INTEGER NOT NULL,
PRIMARY KEY( CUSTOMER_ID ),
CONSTRAINT cust_fk FOREIGN KEY( DETAIL_ID ) REFERENCES DETAILS( DETAIL_ID )
)
CREATE TABLE DETAILS
(
DETAIL_ID INTEGER NOT NULL,
OTHER INTEGER NOT NULL,
PRIMARY KEY( DETAIL_ID )
)
I'd like to map these tables to a single class called Customer, so I have:
#Entity
#Table(name = "CUSTOMERS")
#SecondaryTable(name = "DETAILS", pkJoinColumns=#PrimaryKeyJoinColumn(name="DETAIL_ID"))
public class Customer {
#Id
#GeneratedValue
#Column(name = "CUSTOMER_ID")
private Integer id;
#Column(table = "DETAILS", name = "OTHER")
private Integer notes;
// ...
}
but this works only if DETAIL_ID matches CUSTOMER_ID in the primary table.
So my question is: how can i use a foreign-key field in my primary table to join on the primary-key of the secondary table?
UPDATE
I tried to set:
#SecondaryTable(name = "DETAILS", pkJoinColumns=#PrimaryKeyJoinColumn(name="DETAIL_ID", referencedColumnName="DETAIL_ID"))
but when I run the application I get this exception:
org.hibernate.MappingException: Unable to find column with logical name: DETAIL_ID in org.hibernate.mapping.Table(CUSTOMERS) and its related supertables and secondary tables
For anyone looking for an answer to this, using #SecondaryTable is not the way to join two tables with non-primary key columns, because Hibernate will try to assosiate the two tables by their primary keys by default; you have to use #OneToMany review http://viralpatel.net/blogs/hibernate-one-to-many-annotation-tutorial/ for a solution, here's a code snippet in case that url stops working:
Customer Class:
#Entity
#Table(name="CUSTOMERS")
public class Customer {
#Id
#GeneratedValue
#Column(name="CUSTOMER_ID")
private Integer id;
#ManyToOne
#JoinColumn(name="DETAIL_ID")
private Details details;
// Getter and Setter methods...
}
Details Class:
#Entity
#Table(name="DETAILS")
public class Details {
#Id
#GeneratedValue
#Column(name="DETAIL_ID")
private int detailId;
#Column(name="OTHER")
private String other;
#OneToMany(mappedBy="details")
private Set<Customer> customers;
// Getter and Setter methods...
}
This is easily accessible through hibernate with the following code:
Session session = HibernateUtil.getSessionFactory().openSession();
Query query = session.createQuery("select id, details.other from Customer");
I hope this helps anyone out there spending hours searching for a way to achieve this like I did.
You can use the referenceColumnName attribute of the #PrimaryKeyJoinColumn annotation to define the join column to the referenced table. In fact, by combining use of name/referencedColumnName you can join on arbitrary on both sides, with the constraint that if duplicates are found your ORM provider will throw an exception.