Use same Entity multiple times in another Entity - mysql

I am implementing a Spring Boot server using JPA and Hibernate where there are 2 entities: Channel and Translation.
The Channel entity has two fields (nameTranslations and descriptionTranslations that should hold the name and description of a channel in 2 languages french and english) which are of type Translation as described as follow:
Class Channel
#Entity
#Table(name = "CHANNEL")
public class Channel {
#Id
#Column(name = "ID")
private String id;
#OneToOne(mappedBy = "channel", cascade = CascadeType.ALL)
private Translation nameTranslations;
#OneToOne(mappedBy = "channel", cascade = CascadeType.ALL)
private Translation descriptionTranslations;
}
and
Class Translation
#Entity()
#Table(name = "TRANSLATION")
public class Translation {
#Id
#Column(name = "ID")
private String id;
#Column(length = 1024)
private String en;
#Column(length = 1024)
private String fr;
}
My issue is: How can I implement the previously described logic so that there are 2 Translation fields in the Channel class? I have tried it so far using #OneToOne annotation, but it doesn't work.

I'm not sure what kind of mapping you are trying to achieve, but this will work:
#Entity
#Table(name = "CHANNEL")
public class Channel {
#Id
#Column(name = "ID")
private String id;
#OneToOne(cascade = CascadeType.ALL)
private Translation nameTranslations;
#OneToOne(cascade = CascadeType.ALL)
private Translation descriptionTranslations;
}
or, if you want the columns on the other entity table:
#Entity
#Table(name = "CHANNEL")
public class Channel {
#Id
#Column(name = "ID")
private String id;
#OneToOne(mapped="name", cascade = CascadeType.ALL)
private Translation nameTranslations;
#OneToOne(mapped="description", cascade = CascadeType.ALL)
private Translation descriptionTranslations;
}
#Entity
#Table(name = "TRANSLATION")
public class Translation {
#Id
#Column(name = "ID")
private String id;
#Column(length = 1024)
private String en;
#Column(length = 1024)
private String fr;
#OneToOne
private Channel name;
#OneToOne
private Channel description;
}
See the Hibernate ORM documentation for one-to-one associations.

Related

Hibernate JPA Repeated column in mapping for entity error for bi-directional mapping

I have two entities, sale and sale_details. One sale will have many sale_details, but each sale_detail belongs to only one sale, my current code gives me a Repeated column in mapping for entity error.
Sale:
#Entity
#Table(name="Sales")
public class Sale implements Serializable{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "sale_id", nullable = false)
private int sale_id;
#Column(name = "promotionid_fk")
private int promotionid_fk;
#Column(name = "grand_total", nullable = false)
private double grand_total;
#Column(name = "salespersonid_fk", nullable = false)
private int salespersonid_fk;
#Column(name = "customerid_fk", nullable = false)
private int customerid_fk;
#Column(name = "storeid_fk", nullable = false)
private int storeid_fk;
#Column(name = "expected_date", nullable = false)
private Date expected_date;
#Column(name = "pickup_date")
private Date pickup_date;
#Column(name = "initial_deposit_date", nullable = false)
private LocalDateTime initial_deposit_date;
#Column(name = "initial_deposit_type", nullable = false)
private String initial_deposit_type;
#Column(name = "initial_deposit_amount", nullable = false)
private double initial_deposit_amount;
#Column(name = "final_payment_date")
private LocalDateTime final_payment_date;
#Column(name = "final_payment_type")
private String final_payment_type;
#Column(name = "final_payment_amount")
private double final_payment_amount;
//maps one sale to many sale details relationship
#OneToMany(mappedBy = "sale", fetch = FetchType.LAZY)
private List<SaleDetails> sale_detail_list; //stores list of sale_detail entries where FK saleid_fk field is the ID of this sale
//default constructor, never used
public Sale() {
}
//creates new sale
public Sale(int promotionid_fk, double grand_total, int salespersonid_fk, int customerid_fk, int storeid_fk, Date expected_date, LocalDateTime initial_payment_date, String initial_payment_type, double initial_payment_amount) {
this.promotionid_fk = promotionid_fk;
this.grand_total = grand_total;
this.salespersonid_fk = salespersonid_fk;
this.customerid_fk = customerid_fk;
this.storeid_fk = storeid_fk;
this.expected_date = expected_date;
this.initial_deposit_date = initial_payment_date;
this.initial_deposit_type = initial_payment_type;
this.initial_deposit_amount = initial_payment_amount;
}
Sale_details:
#Entity
#Table(name = "sale_Details")
public class SaleDetails implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "sale_detail_id")
private int saleDetailId;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "saleid_fk")
private Sale sale;
#Column(name = "saleid_fk")
private int saleid_fk;
#Column(name = "productid_fk")
private int productid_fk;
#Column(name = "quantity_sold")
private int quantity_sold;
public SaleDetails(){
}
public SaleDetails(int saleid_fk, int productid_fk, int quantity_sold){
this.saleid_fk = saleid_fk;
this.productid_fk = productid_fk;
this.quantity_sold = quantity_sold;
}
Table structures:
Im trying to make the relationship bi-directional, what am I doing wrong here? From my understanding the owning side of the relationship is the many-to-one on the sale_details entity, and the mappedby in the sale entity is just referencing that there already is a mapping on the inverse side?
Full error stack trace:
Unable to build Hibernate SessionFactory
org.hibernate.MappingException: Repeated column in mapping for entity: com.owl.server.entities.Sale_Details column: saleid_fk (should be mapped with insert="false" update="false")
I would suggest you to follow java naming conventions. According to this roles:
Classes: Class names should be nouns, in mixed case with the first letter of each internal word capitalized.
Variables: Except for variables, all instance, class, and class constants are in mixed case with a lowercase first letter. Internal words start with capital letters.
So, I would suggest you to correct your mapping in the following way:
#Entity
#Table(name="Sales")
public class Sale implements Serializable{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "sale_id", nullable = false)
private int saleId;
#Column(name = "promotionid_fk")
private int promotionId;
// ...
//maps one sale to many sale details relationship
#OneToMany(mappedBy = "sale", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private List<SaleDetails> saleDetails;
// default constructor, should be present
// It is used by hibernate for entity instantiation
public Sale() {
saleDetails = new ArrayList<>();
}
// getters, setters
// The addSaleDetail() and removeSaleDetail() are utility methods that
// synchronize both ends whenever a child element is added or removed.
public void addSaleDetail(SaleDetails saleDetail)
{
saleDetails.add(saleDetail);
saleDetail.setSale(this);
}
public void removeSaleDetail(SaleDetails saleDetail)
{
saleDetails.remove(saleDetail);
saleDetail.setSale(null);
}
}
#Entity
#Table(name = "Sale_Details")
public class SaleDetails implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "sale_detail_id")
private int saleDetailId;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "saleid_fk")
private Sale sale;
// This should be removed
// #Column(name = "saleid_fk")
// private int saleid_fk;
#Column(name = "productid_fk")
private int productId;
// ...
public SaleDetails(){
}
// getters, setters
}
The value in the mappedBy referred to the field name of another side of the association.
You can omit to use the referencedColumnName if the foreign key referred to the primary key field of target entity.
And an example of creation and saving a new Sale:
Sale sale = new Sale();
sale.setPromotionId(1);
// ...
SaleDetails saleDetail1 = new SaleDetails();
saleDetail1.setProductId(2);
// set other fields except sale
sale.addSaleDetail(saleDetail1);
SaleDetails saleDetail2 = new SaleDetails();
saleDetail2.setProductId(3);
// set other fields except sale
sale.addSaleDetail(saleDetail2);
entityManager.persist(sale);

JPA mapping for one-to-many collection of shared data, with user specific values

I have a User model that contains a list of achievements
#Table(name = "user")
#Entity
#NamedEntityGraph(name = "User.achievements",
attributeNodes={
#NamedAttributeNode("achievements")
})
#Data
public class User {
#Id
#NotNull
#Column(name = "username")
private String username;
#Column(name = "password")
private String password;
#ElementCollection(fetch = FetchType.LAZY, targetClass = Achievement.class)
private List<Achievement> achievements = new ArrayList<>();
}
Here's the achievement model
#Entity
#Data
#Table(name = "achievement")
public class Achievement {
#Id
#GeneratedValue(generator = "system-uuid")
#GenericGenerator(name = "system-uuid", strategy = "uuid")
private String achievementId;
#Column(name = "title")
private String title;
#Column(name = "description")
private String description;
#Column(name = "achieved", columnDefinition="BOOLEAN DEFAULT false", nullable = false)
private boolean achieved = false;
user_achievements table generated from #ElementCollection mapping, which atm only contains user and achievement foreign keys
I am looking to move the boolean achieved value to the user_achievements table, ideally without having to create a separate model User_Achievements
I am fairly new to using Jpa, but i feel like this scenario is too basic so there must be a straight forward way to do that i cant seem to locate it
#Entity
class UserAchievement {
#EmbeddableId
UserAchievementId id;
#ManyToOne(fetch=LAZY)
#JoinColumn(name="user_username", insertable=false, updatable=false)
User user;
#ManyToOne(fetch=LAZY)
#JoinColumn(name="achivement_achivement_id", insertable=false, updatable=false)
Achivement achivement;
// and other fields
}
class User {
// ...
#OneToMany(mappedBy="user")
List<UserAchievement> userAchievements;
}
and you need to define UserAchievementId

Advise a dummy on how to structure my query and set up my mapping

Pardon me if this looks too basic, I am just a beginner in springboot. I am trying to create a simple project. I have entity class "company.java" and another "jobs.java"
I have already mapped them such that it will be saving both "companyID,jobID"
now my question is here :
1) how can I ensure that the record is captured into that new table when i feed data from thymeleaf fields. I have tried a dummy entry and its saving jobs into the jobs table but its not capturing anything to insert into the joined table
2) How do I query such that it saves and also when I search a job by its ID it shows me the company.
#Entity
#Table(name = "company_account")
#EntityListeners(AuditingEntityListener.class)
#SecondaryTable(name = "company_profile")
public class CompanyAccount {
private int id;
private String CompanyName;
private String PhoneNumber;
private String Number_of_employees;
private String CompanyURL;
private String OrganisationType;
private String PrimaryIndustry;
private byte[] Logo;
private String Location;
private String DateEstablished;
private String Headquarters;
private String SocialMedia;
public CompanyAccount() {
}
///////////////////////here i tried the mapping
#OneToMany(fetch = FetchType.LAZY, mappedBy = "company_account")
private List<NewJobs> jobs = new ArrayList<NewJobs>();
#Id
// #org.hibernate.annotations.ColumnDefault("001")
#GeneratedValue(strategy = GenerationType.AUTO)
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
//////////////////////////////////
deleted the getters and setters
///////////////////////////////////////////////////////////////
#Entity
#Table(name = "newjobs")
#EntityListeners(AuditingEntityListener.class)
public class NewJobs {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#org.hibernate.annotations.ColumnDefault("001")
private int newjobid;
public NewJobs() {
}
tried my mapping here
#ManyToOne(fetch = FetchType.LAZY)
// #JoinColumn(name = "company_account")
#JoinTable(name = "company_jobs", joinColumns = { #JoinColumn(name = "id") }, inverseJoinColumns = {
#JoinColumn(name = "newjobid") })
private CompanyAccount CompanyAccount;
}
How can I query my insert and also my search by id ?

Nested one to many relationship jpa spring boot

I have three classes - Document, Page, Sentence. A Document will have multiple Pages & each Page will have multiple Sentences. I'm trying to map One to Many relationship using Spring Data JPA annotation. But it only works when there are only one layer like - Document>Page. Doesn't work while it's Document>Page>Sentence.
Can anyone please give me a solution for how to do it for nested one to many relationship ?
My classes are given below.
#Entity
#Table(name = "DOCUMENT")
public class Document implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "FILEID")
#GeneratedValue(strategy = GenerationType.AUTO)
private long idFile;
#Lob
#Column(name = "CONTENT")
private byte[] content;
#Column(name = "NAME")
private String name;
#Column(name = "ID_MAIL_USER")
private String idMailUser;
#Column(name = "NUM_PAGES")
private int numPages;
#Column(name = "TO_ANALIZE")
private boolean toAnalize;
#Column(name = "HASH")
private String hash;
#Column(name = "EXTENSION")
private String extension;
#Column(name = "SIZE")
private double size;
#Column(name = "LINK_TO_DRIVE_FILE")
private String linkToDriveFile;
#Column(name="PATH")
private String path;
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
#Column(name = "PAGES")
private List<Page> pages = new ArrayList<>();
// Setter Getters
}
.
#Entity
#Table(name = "PAGE")
public class Page implements Serializable {
#Id
#Column(name = "PAGE_ID")
#GeneratedValue(strategy = GenerationType.AUTO)
private long idPage;
#Column(name = "PAGE_NUMBER")
private int pageNum;
#Lob
#Column(name = "CONTENT")
private String content;
#ManyToMany(cascade = CascadeType.ALL)
#Column(name = "SENTENCES")
private List<Sentence> sentences = new ArrayList<>();
// Setter Getters
}
.
#Entity
#Table(name = "SENTENCE")
public class Sentence implements Serializable {
//private long idFile;
//private long idPage;
#Id
#Column(name = "SENTENCE_ID")
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#Column(name = "PAGE_NUMBER")
private int pageNumber;
#Column(name = "ORDER")
private int ord;
#Column(name = "CONTENT")
private String content;
#Column(name = "HASH")
private String hash;
// Setter Getters
}
Your OneToMany mappings are incorrect. Correct it as follows
#Entity
#Table(name = "DOCUMENT")
public class Document implements Serializable {
......
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
#JoinColumn(name = "DOCUMENT_ID") //Name the foreign key column in PAGE table to DOCUMENT_ID
private List<Page> pages = new ArrayList<>();
}
#Entity
#Table(name = "PAGE")
public class Page implements Serializable {
....
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name = "PAGE_ID") //Name the forein key column in PAGE table to PAGE_ID
private List<Sentence> sentences = new ArrayList<>();
}
Use #JoinColumn annotation instead of #Column to give the name of the foreign key that do the physical mapping between tables in your database.
#Entity
#Table(name = "DOCUMENT")
public class Document implements Serializable {
private static final long serialVersionUID = 1L;
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy="document")
#Column(name = "PAGES")
private List<Page> pages = new ArrayList<>();
}
#Entity
#Table(name = "PAGE")
public class Page implements Serializable {
#ManyToOne
#JoinColumn(name="DOCUMENT_ID")
private Document document;
#ManyToMany(cascade = CascadeType.ALL, mappedBy="pages")
#Column(name = "SENTENCES")
private List<Sentence> sentences = new ArrayList<>();
}
#Entity
#Table(name = "SENTENCE")
public class Sentence implements Serializable {
#ManyToMany(mappedBy="sentences")
private List<Page> pages;
}
Here a Document One to Many relationship with Pages.
So.. we need define mappedBy in the entity we want to map another entity.. so in this case
#OneToMany(mappedBy="document",cascade = CascadeType.ALL, orphanRemoval = true)
and in referenced entity i.e. Pages we want foreign key DOCUMENT_ID, so we have to define it using
#ManyToOne
#JoinColumn(name="DOCUMENT_ID")

Foreign Keys in Spring Boot (MySQL, Hibernate, JPA)

I am trying to write a RESTful API using Spring Boot and I am not able to figure out a way to map my relations in the database. I have a User and a Reports table. Each User can have multiple Reports, and a single report consists of "FROM USER" and "TO USER" columns to indicate who sent the report and to whom. My User ID is the primary key and for the Report table, I am generating REPORT ID as the primary key using AUTO INCREMENT. Here is my User model class -
#Entity
#Table (name = "user")
#EntityListeners(AuditingEntityListener.class)
public class User {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String firstName;
private String lastName;
private String email;
private String password;
#OneToMany(mappedBy = "user",cascade = CascadeType.ALL)
private List<Report> reportReceivedList;
#OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
private List<Report> reportSentList;
/* Getters and setters ..... */
}
Here is my Report Model class -
#Entity
#Table (name = "report")
#EntityListeners(AuditingEntityListener.class)
public class Report {
#Id
#Column (name = "id")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#ManyToOne()
#JoinColumn(name = "from_user_id")
private Long fromUserId; //THIS SHOULD BE FROM "USER" TABLE
#ManyToOne()
#JoinColumn(referencedColumnName = "to_user_id")
private Long toUserId; //THIS SHOULD BE FROM "USER" TABLE
#Temporal(TemporalType.DATE)
#CreatedDate
private Date createdAt;
private String observation;
private String context;
//Other variables and getters and setters .....
}
Can someone please show me a way to correctly define this relationship. My current model doesn't work. Also, I want rows from REPORT class to be deleted as soon as a user is deleted. Thanks!
I finally fixed it by changing my User class as follows -
#OneToMany(cascade = CascadeType.ALL, targetEntity = Report.class)
#JoinColumn(name = "to_user_id")
private List<Report> reportReceivedList;
#OneToMany(cascade = CascadeType.ALL, targetEntity = Report.class)
#JoinColumn(name = "from_user_id")
private List<Report> reportSentList;
And by changing my Report class as -
#Column(name = "from_user_id")
private Long fromUserId;
#Column(name = "to_user_id")
private Long toUserId;