I'm mapping classes via Hibernate and I need to map multiple ID for Relationship.
All ID's extend from BaseEntity. How can I implement multiple ID mapping for Relationship which contains Foreign Key for User in DataBase ?
Basicly fields userIdOne and userIdTwo in Relationship has to contain user's id which send request.
User extend own ID from BaseEntity.
Each time I run it - get en error:
This class [class com.mylov.springsocialnetwork.model.Relationship]
does not define an IdClass
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#MappedSuperclass
#EqualsAndHashCode
public class BaseEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
}
#Builder
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#EqualsAndHashCode(exclude = {"posts"}, callSuper = false)
#Entity
public class User extends BaseEntity {
private String userName;
private String realName;
private String email;
private String phoneNumber;
private LocalDate birthDate;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "userPosted")
private Set<Post> posts = new HashSet<>();
private String password;
public User(Long id, String userName, String realName, String email, String phoneNumber, LocalDate birthDate,
Set<Post> posts, String password) {
super(id);
this.userName = userName;
this.realName = realName;
this.email = email;
this.phoneNumber = phoneNumber;
this.birthDate = birthDate;
this.posts = posts;
this.password = password;
}
}
#Builder
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#Entity
public class Relationship implements Serializable {
//#Id not working
private Long userIdFrom;
//#Id
private Long userIdTo;
#Enumerated(value = EnumType.STRING)
private RelationshipStatus status;
private LocalDate friendsRequestDate;
}
It appears that you are looking to establish a Relationship between two different users. This would mean that each Relationship is an object/entity of its own and should have its very own #Id (unrelated to user IDs).
The linkage to each User that form part of this Relationship should be mapped as foreign keys instead (probably #ManyToOne and a #JoinColumn).
For example:
#Entity
public class Relationship implements Serializable {
#Id
private Long relationshipId;
#ManyToOne(...)
#ForeignKey(name="FK_USER_ONE") //for generation only, it isn't strictly required
#JoinColumn(name="from")
private Long userIdFrom;
#ManyToOne(...)
#ForeignKey(name="FK_USER_TWO") //for generation only, it isn't strictly required
#JoinColumn(name="to")
private Long userIdTo;
#Enumerated(value = EnumType.STRING)
private RelationshipStatus status;
private LocalDate friendsRequestDate;
}
Edit:
It isn't required to specify the #ForeignKey annotations. They will be used if the database tables are generated automatically (ok for testing, but usually not something you'll want in production) and will create the FOREIGN KEY constraint on the table accordingly, but JPA mapping will work fine without it, because it takes the relationships from your defined model, not from the database itself.
Related
I'm currently working on developing a recipe application and I'm having trouble with DB table generation.
Here are the Entity files I'm using:
// Recipe.java
#Data
#Entity
#AllArgsConstructor
#NoArgsConstructor
#Table(name = "recipes")
public class Recipe {
#Id
#GeneratedValue
private int id;
private String name;
private String description;
private String instruction;
#ManyToOne
private User user;
#OneToMany(cascade=CascadeType.ALL)
private List<RecipeIngredient> ingredients = new ArrayList<>();
}
// Ingredient.java
#Data
#Entity
#AllArgsConstructor
#NoArgsConstructor
#Table(name = "ingredients")
public class Ingredient {
#Id
#GeneratedValue
private int id;
private String name;
}
// RecipeIngredient.java
#Data
#Entity
#AllArgsConstructor
#NoArgsConstructor
public class RecipeIngredient {
#Id
#GeneratedValue
private int id;
#ManyToOne
private Ingredient ingredient;
private String amount;
}
Spring Boot Automatically creates tables for me but I just wanna have one table for RecipeIngredient, but it creates two tables for them.
It works perfectly fine but the thing I want is just how to make these two tables into one or make spring boot not generate one of them.
If you want recipe_ingedients table only delete recipeIngredient Entity Class and if you want to keep recipe_ingredient table remove this:
#OneToMany(cascade=CascadeType.ALL)
private List<RecipeIngredient> ingredients = new ArrayList<>();
When I run my project, the Hibernate creates automatically tables with wrong names.
I have two tables User and Role and also three classes:
abstract class IdField.java:
#Entity
public abstract class IdField {
#Id #GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long id;
//constructors and getters setters
User.java class:
#Entity
#Table(name = "user", schema = "quiz_app")
public class User extends IdField{
#Column(name = "user_name")
private String userName;
#Column(name = "password")
private String password;
#Column(name = "first_name")
private String firstName;
#Column(name = "last_name")
private String lastName;
#Column(name = "email")
private String email;
#ManyToMany(fetch = FetchType.EAGER)
private Collection<Role> roles = new ArrayList<>();
//constructors and getters setters
and Role.java class:
#Entity
#Table(name = "role", schema = "quiz_app")
public class Role extends IdField{
#Enumerated(EnumType.ORDINAL)
#Column(name = "role_name")
private RoleName roleName;
//constructors and getters setters
And Hibernate creates two tables with wrong names as id_field and id_field_roles:
but I want table names as it is in #Table annotation like "user" and "role"
Get familiar with inheritance strategies:
https://thorben-janssen.com/complete-guide-inheritance-strategies-jpa-hibernate/
It seems to me you are looking for #MappedSuperclass
If you just want to share state and mapping information between your entities, the mapped superclass strategy is a good fit and easy to implement. You just have to set up your inheritance structure, annotate the mapping information for all attributes and add the #MappedSuperclass annotation to your superclass. Without the #MappedSuperclass annotation, Hibernate will ignore the mapping information of your superclass.
On top of that: If your shared part is only id field, as the name suggests, inheritance looks like overkill.
I am using Spring Boot with Spring Data JPA. I have two tables named User and Employee.
Employee.java
#Data
#NoArgsConstructor
public class Employee implements Serializable
{
private static final long serialVersionUID = -3732596549369515261L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
private String designation;
private Date dateOfJoining;
private String workLocation;
#Column(unique = true)
private Long contactNo;
#Column(unique = true)
private String email;
private Date dateOfLeaving;
}
User.java
#Entity
#Data
#NoArgsConstructor
public class User
{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String username;
private String password;
}
I want to create a relation between Employee.email with User.username. Will this be possible via any JPA annotations.
I tried with Mappings from JPA and none of them is working as the User.username is String, unlike Employee object.
I am trying to add multi-language to the description and title fields of one of my Entities but without success. My Entity is like below and my database is MySQL:
#Data
#AllArgsConstructor
#NoArgsConstructor
#Entity
#Table(name = "project")
public class ProjectEntity implements Serializable {
#Id
#Column(name="id")
private Integer id;
#Column(name="team_size")
private Integer teamSize;
#Column(name="description")
private String description;
#Column(name="title")
private String title;
#OneToMany
private List<DetailsEntity> details;
}
I alreaady tried to add a projectDetails entity that contains the description and title, but as I need multilanguage, the Project will now have a list of ProjectDetails in my backend, what I don't need.
Here is what the projectDetails could looks like:
#Data
#AllArgsConstructor
#NoArgsConstructor
#Entity
#Table(name = "project_details")
public class ProjectDetails implements Serializable {
#Id
#Column(name="id")
private Integer id;
#Column(name="title")
private String title;
#Column(name="description")
private String description;
#Column(name="language")
private String language;
#Column(name="project_id")
private Integer projectId;
}
I would like to be able to do something with the JPA repository requests, like this:
#Repository
public interface ProjectEntityRepository extends JpaRepository<ProjectEntity, Integer> {
#Query("select p from ProjectEntity p left outer join ProjectDetails d on p.id=d.project_id and d.language=:language")
List<ProjectEntity> findAllForLanguage(String language);
}
Any idea on how to change part of this to return the Project entity with values of only 1 ProjectDetails?
Thank you
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.