I work with mySQL, hibernate and Spring Datas and I want to link a table with more than one entity.
The table looks like this but more complex (with many-to-one relations...) :
CREATE TABLE FOOBAR (
id BIGINTEGER NOT NULL AUTO_INCREMENT,
type ENUM('FOO', 'BAR'),
name VARCHAR(30),
foo_style ENUM('ONE', 'TWO')),
PRIMARY KEY(id);
The entities that I want to create. I want a generic table that cans recover all the entries, and two tables that cans recover only the rows corresponding to the correct enum :
#Table
public class FooBar {
#Id
#Column
private String id;
#Column
#Enumerated(EnumType.STRING)
private Type type;
#Column
private String name;
#Column
#Enumerated(EnumType.STRING)
private FooStyle fooStyle;
}
#Table //On type foo
public class Foo {
#Id
#Column
private String id;
#Column
private String name;
#Column
#Enumerated(EnumType.STRING)
private FooStyle fooStyle;
}
#Table //On type bar
public class Bar {
#Id
#Column
private String id;
#Column
private String name;
}
Thanks in advance !
Related
I have a situation with repeatable class fields which I want to mark as #embeddable, however the question is - does JPA allow re-utilizing a class multiple times as embeddable in other different classes?
E.g. my embeddable class looks as follows:
#Embeddable
#Data
public class Audit{
private String name;
private Audit auditor;
private LocalDateTime creationDate;
}
Is it possible to embed the Audit into multiple different classes as for ex.:
#Entity
#Table(name = "BANK")
public class Bank{
#Id
private Long id;
#Column(name = "BANK_NAME")
private String bankName;
#Embedded
private Audit audit;
}
AND
#Entity
#Table(name = "CORPORATION")
public class Corporation{
#Id
private Long id;
#Column(name = "CORPORATION_NAME")
private String corporationName;
#Embedded
private Audit audit;
}
Historically Hibernate called these components. JPA calls them embeddables. Either way, the concept is the same: a composition of values.
Most often, embeddable types are used to group multiple basic type mappings and reuse them across several entities.
Java Code Example:
#Data
#Entity(name = "Book")
public class Book {
#Id
#GeneratedValue
private Long id;
private String title;
private String author;
private Publisher publisher;
}
#Data
#Embeddable
public static class Publisher {
#Column(name = "publisher_name")
private String name;
#Column(name = "publisher_country")
private String country;
}
And this is SQL to show how your table should look like:
create table Book (
id bigint not null,
author varchar(255),
publisher_country varchar(255),
publisher_name varchar(255),
title varchar(255),
primary key (id)
)
More details can be found in the documentation :)
I want to do :
create table user (
id bigint primary key auto_increment,
firstname varchar(128),
lastname varchar(128),
street varchar(128),
zipcode mediumint,
city varchar(128)
)
then :
#Entity
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String firstname;
private String lastname;
private Address address; // Here I want an Address rather than street, zip, and city directly inside User
...
}
and :
public class Address {
private String street;
private Integer zipcode;
private String city;
...
}
(that is an example)
How to do that with Hibernate ? #OneToOne ? The problem seems simple and since I can't find the solution around here, it must be obvious.
First, annotate your Address class with #Embeddable:
#Embeddable
public class Address {
/*class definition here*/
...
}
And then update your user class in this way:
#Entity
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String firstname;
private String lastname;
#Embedded
private Address address;
...
}
That's it. If you want a more complex example look here. Just pay attention to model classes definition, it makes no difference if you are using Spring Boot or not as long as you handle your database with JPA.
You can associate entities through a one-to-one relationship using #OneToOne annotation.
#Entity
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Address address;
#OneToOne(cascade = CascadeType.ALL)
#PrimaryKeyJoinColumn
public Address getAddress()
{
return address;
}
}
Reference:
https://docs.jboss.org/hibernate/annotations/3.5/reference/en/html/entity.html#entity-mapping-association
I have such a simple scheme
and the following entities:
#Entity
public class Ticket {
#Id
#GeneratedValue
private Integer id;
#ManyToOne
private Event event;
#OneToOne
private User user;
#Embedded
private Seat seat;
private TicketState state;
private Float price;
// getters, setters, etc.
#Entity
public class Event {
#Id
#GeneratedValue
private Integer id;
#OneToOne
private Movie movie;
#Embedded
private Auditorium auditorium;
private LocalDateTime startDateTime;
#OneToMany
private Set<Ticket> tickets = new HashSet<>();
// getters, setters, etc.
#Entity
public class User {
#Id
#GeneratedValue
private Integer id;
#Enumerated(EnumType.STRING)
private UserRole role;
private String name;
private String email;
private Instant birthday;
#OneToMany
private List<Ticket> tickets = new ArrayList<>();
private boolean lucky;
// getters, setters, etc.
#Embeddable
public class Auditorium {
private Integer id;
private String name;
private Integer seatsNumber;
#ElementCollection
private List<Integer> vipSeats;
// getters, setters, etc.
Also these entities was added to hibernate.cfg.xml.
Than I run app I have the following exception:
Caused by: org.hibernate.MappingException: Repeated column in mapping for entity: com.epam.spring.core.domain.Event column: id (should be mapped with insert="false" update="false")
At first glance I don't see any duplications in Event, as mentioned in exception. What should I fix in entities mapping description to resolve the problem according my scheme? Thank you!
Both Event and Auditorium map to column named id.
Specify a different column name in Auditorium or use #AttributeOverride in Event to override the default name.
When you map an entity with annotations, you do not need to repeat yourself on hibernate.cfg.xml. Try to delete it e run your code again.
Updating my answer based on Dragan Bozanovic's, Auditorium should NOT have an #Id annotated field (but we can't see that from your code, if it has).
I'd like to create a composite primary key with hibernate. Usually I'd go for #IdClass.
But this time I want to use a foreign key also inside the composite primary key.
Question: is that possible at all?
Example:
#Entity
class Person {
long id;
}
class CarPK implements Serializable {
private int code;
private String name;
public CarPK(int code, String name) {
this.code = code;
this.name = name;
}
}
#Entity
#IdClass(CarPK.class)
class Car {
#Id
private int code;
#Id
private String name;
//can I also mark "person.id" with #Id?
#ManyToOne
#JoinColumn(name = "fk_person_id", foreignKey = #ForeignKey(name = "fk_person"))
private Person person; //assume car is shared
}
The person reference will show in database as fk_person_id. Is it possible to also add this column to the primary key of the car table?
So I'd be getting similar to: CONSTRAINT car_pkey PRIMARY KEY (code, name, fk_person_id)?
Update:
#ManyToOne
#JoinColumn(name = "id")
private Person person;
Results in: Property of #IdClass not found in entity path.to$Car: id
Yes, you can add the #Id to the join column, but you must use the key type in your IdClass. I'm doing exactly the same thing in my current project.
#Entity
#IdClass(MyIdClass.class)
public class MyObject {
#Id
private String key;
#Column
#Lob
private String value;
#ManyToOne(cascade = CascadeType.PERSIST)
#Id
#JoinColumn(name = "id")
private MyOtherObject otherObject;
...
and
public class MyIdClass implements Serializable {
private long otherObject;
private String key;
...
MyOtherObject.id is a long in this scenario.
Database
*user_account*
id (PK)
email
password
*user_detail*
id(PK)(FK)
name
city
Entities
#Table(name="user_detail")
public class UserDetail implementsSerializable{
#Id private Integer id;
...
#OneToOne
#JoinColumn(name="id")
private UserAccount userAccount;
}
#Table(name="user_account")
public class UserAccount implementsSerializable{
#Id private Integer id;
#OneToOne(mappedBy="userAccount")
private UserDetail userDetails;
}
Error
Exception Description: Multiple writable mappings exist for the field [user_detail.ID]. Only one may be defined as writable, all others must be specified read-only.
If the ID in UserAccount is both a primary key and a foreign key, then you should declare it as a single field and map it appropriately. Like this:
#Entity
public class UserAccount implements Serializable {
#Id
#OneToOne(mappedBy="userAccount")
private UserDetail userDetails;
}
Or else using #MapsId.
However, i suspect that what you really want is a single class spread over two tables:
#Entity
#Table(name = "user_account")
#SecondaryTable(name = "user_detail")
public class User implements Serializable {
#Id
private int id;
private String email;
private String password;
#Column(table = "user_detail")
private String name;
#Column(table = "user_detail")
private String city;
}
You cannot have both #Id private Integer id; and #JoinColumn(name="id"), you must remove one of them: I doubt that you really need a primary key in the details, so just remove the #Id line from there.