I am currently trying my hand at Java Spring Boot and would just like to provide some data via API.
Unfortunately, I have not gotten any further for hours if I made a mistake.
Error message:
org.hibernate.MappingException: Repeated column in mapping for entity: com.acm500.db.CocktailIngredient column: cocktail_id (should be mapped with insert="false" update="false")
Database structure:
CocktailIngredient Entity:
#Table(name = "cocktail_ingredients")
#Entity
public class CocktailIngredient {
#EmbeddedId
private CocktailIngredientId id;
#Column(name = "amount", nullable = false)
private String amount;
#Column(name = "amount_ml")
private String amountMl;
#Column(name = "created_at")
private Instant createdAt;
#Column(name = "updated_at")
private Instant updatedAt;
}
CocktailIngredientId:
#Embeddable
public class CocktailIngredientId implements Serializable {
private static final long serialVersionUID = -6965389309722862577L;
#Column(name = "cocktail_id", nullable = false, updatable = false, insertable = false)
private Long cocktailId;
#Column(name = "ingredients_id", nullable = false)
private Long ingredientsId;
#Column(name = "strength_id", nullable = false)
private Long strengthId;
#Column(name = "orderNo", nullable = false)
private Integer orderNo;
}
I would appreciate any help. Maybe someone has already made this mistake.
Related
I'm new on Java. I'm doing a HTTPDeleting with JpaRepository(DeleteById) and i recived the following error: ConstraingViolationException - FK_QUESTION_ID cannot be null.
#Entity
#Data
public class Question {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "QUESTION_ID")
private int id;
#Column(nullable = false)
private String title;
#Column(nullable = false)
private String description;
// QUESTION_ID => FOREING KEY COLUMN
#OneToMany(orphanRemoval = true, fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name = "FK_QUESTION_ID")
private List<Answer> answers;
#Column(name = "LIKE_COUNT")
private int likeCount;
#Column(name = "INTEREST_AREA_ID", nullable = false)
private int interestAreaId;
#Column(name = "USER_ID", nullable = false)
private int userId;
#Column
private boolean active;
#Column(name = "CREATED_DT", nullable = false)
private Date createdDate;
}
#Entity
#Data
public class Answer {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ANSWER_ID")
private int answerId;
#Column
private String description;
#Column(name = "LIKE_COUNT")
private int likeCount;
#Column(name = "USER_ID", nullable = false)
private int userId;
#Column
private boolean active;
#Column(name = "CREATED_DT", nullable = false)
private Date createdDate;
#Column(name = "FK_QUESTION_ID")
private int questionId;
}
I read that use CascadeType.Delete is not a good practice, so i used orphanRemoval but even in this way doesn't worked.
questionRepository.deleteById(id);
Your setup is almost correct, except you need to change couple of things here and there. Two important things are:
mappedBy = "question" in the parent entity (Question) targets question field of child entity (Answer)
#JoinColumn should be placed in the child class, through which you specify the column name FK_QUESTION_ID in the Answer table.
Hope, it helps.
#Entity
#Data
public class Question {
#OneToMany(mappedBy = "question", orphanRemoval = true, fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private List<Answer> answers;
}
#Entity
#Data
public class Answer {
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "FK_QUESTION_ID", nullable = false)
private Question question;
// since you seem to use lombok, you can also use
// answer.getQuestion().getId() instead of this method
public int getQuestionId() {
return this.question.getId(); // question lazy fetching
}
}
I have an Bid entity defined as follows
#ToString
#NoArgsConstructor
#AllArgsConstructor
#Setter
#Getter
#Entity
#Table(name = "bid_details")
public class Bid {
private enum STATUS { INITIATED, DRAFT, COMPLETED }
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", nullable = false, updatable = false)
private Integer id;
#Column(name = "govt_bid_id", nullable = false)
private String govtBidNumber;
#Temporal(TemporalType.DATE)
#Column(name = "release_date", nullable = false)
#JsonFormat(pattern = "dd-MM-yyyy")
private Date releaseDate;
#ManyToOne(optional = false)
#JoinColumn(name = "created_by", referencedColumnName = "id", updatable = false, nullable = false)
private User createdBy;
#Temporal(TemporalType.DATE)
#Column(name = "created_date", nullable = false)
#CreationTimestamp
private Date createdDate;
#ManyToOne
#JoinColumn(name = "updated_by", referencedColumnName = "id", updatable = false, nullable = false)
private User updatedBy;
#Enumerated(EnumType.STRING)
#Column(name = "status", nullable = false)
private STATUS status;
#Column(name = "avg_turnover")
private String avgTurnover;
#Convert(converter = StringListConverter.class)
#Column(name = "docs_required", columnDefinition = "json")
private List<String> docsRequired;
#Enumerated(EnumType.STRING)
#Column(name = "status", nullable = false)
private STATUS status;
}
and the corresponding columns are present in the bid_details tables. I have bid repository defined as follows:
public interface BidRepository extends JpaRepository<Bid, Integer> {
}
now when I try to access data by id using findById it is throwing No Value Present exception whereas if I try to access the data using findAllById I am getting correct result. Not able to figure out what's causing this weird behaviour.
Also, if I execute findAll first and then findById it is giving the correct result.
I am using spring-boot version 2.1.1
following is code where the entity is saved in the db
public Bid addBid(BidRequest bidRequest) {
User user = userRepository.findById(bidRequest.getCreatedBy()).get();
Bid bid = new Bid();
modelMapper.map(bidRequest, bid);
bid.setCreatedBy(user);
return bidRepository.save(bid);
}
BidRequest class is as follows:
#ToString
#NoArgsConstructor
#AllArgsConstructor
#Setter
#Getter
public class BidRequest {
private String govtBidNumber;
#Temporal(TemporalType.DATE)
#JsonFormat(pattern = "yyyy-MM-dd")
private Date releaseDate;
#Temporal(TemporalType.DATE)
private Date endDate;
private int createdBy;
#Temporal(TemporalType.DATE)
#JsonFormat(pattern = "yyyy-MM-dd")
private Date createdDate;
private int updatedBy;
private String status;
private List<String> docsRequired;
}
Have you tried orElse like this
findById(id).orElse(null);
Because findById returns an Optional object so you have to write orElse() after findById()
I have a entity bean with a relation #ManyToOne that is in join on one column.
#Entity
#Table(name = "work_order")
public class WorkOrder implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
#SequenceGenerator(name = "sequenceGenerator")
private Long id;
#NotNull
#Column(name = "id_order", nullable = false)
private String idOrder;
#Column(name = "description")
private String description;
#Enumerated(EnumType.STRING)
#Column(name = "status")
private StatusOrder status;
#Column(name = "creation_date")
private Instant creationDate;
#Column(name = "closing_date")
private Instant closingDate;
#Column(name = "client_id")
private Long clientId;
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST) #NotFound (action = NotFoundAction.IGNORE)
#Fetch(FetchMode.JOIN)
#JoinColumn(name = "account", insertable = false, updatable = false, nullable = true)
private AnagraficaClienti account;
And the second Entity
#Entity
#Table(name = "es_account")
public class AnagraficaClienti implements Serializable {
private static final long serialVersionUID = 1L;
// da rimettere a #NotNull
#Column(name = "fk_cod_azienda", nullable = true)
private String fk_cod_azienda;
#Id
#NotNull
#Column(name = "account", nullable = false)
private String account;
// da rimettere a #NotNull
#Column(name = "tipo_cli_for", nullable = true)
private String tipoClienteFornitore;
#Column(name = "tipo_account", nullable = true)
private String tipoAccount;
....
The "es_account" table has three not nullable primary key(fk_cod_azienda, account, tipo_cli_for) and the relation with the "work_order" table is by account column.
My problem is that sometimes it is possible that the user insert or update WorkOrder with a null account value and that is not avoid by AnagraficaClienti entity because it expects a non null(and not duplicate) value.
Are there any possible way to bypass the join with AnagraficaClienti when account is null?
In my point of view, #ManyToOne is violate OOP design principle due to the creation of redundant relation. Instead, i always create a #OneToMany relation with a list of related entities. To specify the relation as nullable, just add the nullable=true property in #JoinColumn. With #ManyToOne, you must specify property optional=true. Lets try and see if it works.
WorkOrder
#Entity
#Table(name = "work_order")
public class WorkOrder implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
#SequenceGenerator(name = "sequenceGenerator")
private Long id;
#NotNull
#Column(name = "id_order", nullable = false)
private String idOrder;
#Column(name = "description")
private String description;
#Enumerated(EnumType.STRING)
#Column(name = "status")
private StatusOrder status;
#Column(name = "creation_date")
private Instant creationDate;
#Column(name = "closing_date")
private Instant closingDate;
#Column(name = "client_id")
private Long clientId;
AnagraficaClienti
#Entity
#Table(name = "es_account")
public class AnagraficaClienti implements Serializable {
private static final long serialVersionUID = 1L;
// da rimettere a #NotNull
#Column(name = "fk_cod_azienda", nullable = true)
private String fk_cod_azienda;
#Id
#NotNull
#Column(name = "account", nullable = false)
private String account;
// da rimettere a #NotNull
#Column(name = "tipo_cli_for", nullable = true)
private String tipoClienteFornitore;
#Column(name = "tipo_account", nullable = true)
private String tipoAccount;
#OneToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE} )
#JoinColumn(name = "account", nullable = true)
private List<WorkOrder> workOrders;
When you want to insert the work order to the database:
workOrderRepository.save(workOrder);
When you want to create the relationship:
AnagraficaClienti client = anagraficaClientiRepository.findById(...);
client.getWorkOrders().add(newWorkOrder);
Is it possible to create one column for bi-directional relationship?
My Entities:
#Entity
#Table(name = "subscription")
#Proxy(lazy = false)
public class Subscription {
#Id #GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name = "subscription_id")
private long id;
#Column(name = "userid", nullable = false)
private String userId;
#Column(name = "saledate", nullable = false)
#Temporal(TemporalType.DATE)
private Date saleDate;
#Column(name = "finishdate", nullable = false)
#Temporal(TemporalType.DATE)
private Date finishDate;
#Column(name = "price", nullable = false)
private long price;
#Column(name = "description", nullable = false)
private String description;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "subscription")
private List<VisitDate> visitDates = new ArrayList<>();
}
#Entity
#Table(name="visitdate")
public class VisitDate {
#Id #GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name = "id")
private long id;
private long subscription;
#Column(name = "date", nullable = false)
#Temporal(TemporalType.DATE)
private Date date;
#ManyToOne
#JoinColumn(name="subscription_id")
private Subscription associatedSub;
}
Now I see two columns in the database and little bit confused.
I don't want to save the same data but want to display a report about how many users visit on some day.
Update:
You are not required to create a separate field "subscription" in VisitDate class. Hibernate will automatically create a field to store subscription id. The code needs to be slightly changed.
#Entity
#Table(name = "subscription")
public class Subscription {
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
#Column(name = "subscription_id")
private long id;
#Column(name = "userid", nullable = false)
private String userId;
#Column(name = "saledate", nullable = false)
#Temporal(TemporalType.DATE)
private Date saleDate;
#Column(name = "finishdate", nullable = false)
#Temporal(TemporalType.DATE)
private Date finishDate;
#Column(name = "price", nullable = false)
private long price;
#Column(name = "description", nullable = false)
private String description;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "associatedSub")
private List<VisitDate> visitDates = new ArrayList<>();
}
Notice, that I have changed the mappedBy property to point at associatedSub in the above class.
#Entity
#Table(name="visitdate")
public class VisitDate {
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
#Column(name = "id")
private long id;
#Column(name = "date", nullable = false)
#Temporal(TemporalType.DATE)
private Date date;
#ManyToOne
#JoinColumn(name="subscription_id")
private Subscription associatedSub;
}
You can use Uni-Directional relationship for the same purpose. You just need to add a list/set of Visits for a particular subscription, You don't have to create a list of subscription for a particular visit.
for reference Visit [Java JPA] :(https://en.wikibooks.org/wiki/Java_Persistence/OneToMany#Undirectional_OneToMany.2C_No_Inverse_ManyToOne.2C_No_Join_Table_.28JPA_2.0_ONLY.29)!
#Entity
#Table(name = "subscription")
#Proxy(lazy = false)
public class Subscription {
#Id #GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name = "subscription_id")
private long id;
#Column(name = "userid", nullable = false)
private String userId;
#Column(name = "saledate", nullable = false)
#Temporal(TemporalType.DATE)
private Date saleDate;
#Column(name = "finishdate", nullable = false)
#Temporal(TemporalType.DATE)
private Date finishDate;
#Column(name = "price", nullable = false)
private long price;
#Column(name = "description", nullable = false)
private String description;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "subscription")
private List<VisitDate> visitDates = new ArrayList<>();
}
#Entity
#Table(name="visitdate")
public class VisitDate {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name = "id")
private long id;
private long subscription;
#Column(name = "date", nullable = false)
#Temporal(TemporalType.DATE)
private Date date;
}
I've creating entities from a data-source using Netbeans 7.4.
And I have an error which arises with all entities which have a composite primary key. The error can be seen below.
I have searched this problem on stack-overflow and its is usually because people have not defined the join columns. but I have this done. I'm also unsure how there is errors in code generated by netbeans.
Here is an image of my MySQL database which I forward engineered to create these entitys:
Any help would be greatly appreciated !
Here is the only the relevant code
Absence entity:
public class Absence implements Serializable {
private static final long serialVersionUID = 1L;
#EmbeddedId
protected AbsencePK absencePK;
#Basic(optional = false)
#NotNull
#Column(name = "idAbsence")
private int idAbsence;
#Basic(optional = false)
#NotNull
#Column(name = "Date")
#Temporal(TemporalType.DATE)
private Date date;
#Size(max = 35)
#Column(name = "type")
private String type;
#Lob
#Size(max = 65535)
#Column(name = "remark")
private String remark;
#JoinColumn(name = "TimeTable_Period", referencedColumnName = "Period", insertable = false, updatable = false)
#ManyToOne(optional = false)
private Timetable timetable;
#JoinColumn(name = "Student_idStudent", referencedColumnName = "idStudent", insertable = false, updatable = false)
#ManyToOne(optional = false)
private Student student;
#JoinColumn(name = "Class_idClass", referencedColumnName = "idClass", insertable = false, updatable = false)
#ManyToOne(optional = false)
private Class class1;
AbsencePK entity:
#Embeddable
public class AbsencePK implements Serializable {
#Basic(optional = false)
#NotNull
#Column(name = "Class_idClass")
private int classidClass;
#Basic(optional = false)
#NotNull
#Column(name = "Student_idStudent")
private int studentidStudent;
#Basic(optional = false)
#NotNull
#Column(name = "TimeTable_Period")
private int timeTablePeriod;
public AbsencePK() {
}
public AbsencePK(int classidClass, int studentidStudent, int timeTablePeriod) {
this.classidClass = classidClass;
this.studentidStudent = studentidStudent;
this.timeTablePeriod = timeTablePeriod;
}
Error:
Caused by: Exception [EclipseLink-7220] (Eclipse Persistence Services - 2.5.0.v20130507-3faac2b):
org.eclipse.persistence.exceptions.ValidationException
Exception Description: The #JoinColumns on the annotated element [field timetable] from the entity class [class com.fyp.simstest.Absence] is incomplete.
When the source entity class uses a composite primary key, a #JoinColumn must be specified for each join column using the #JoinColumns.
Both the name and the referencedColumnName elements must be specified in each such #JoinColumn.
at org.eclipse.persistence.exceptions.ValidationException.incompleteJoinColumnsSpecified(ValidationException.java:1847)
EDIT
TimeTable
#Entity
#Table(name = "timetable")
#XmlRootElement
#NamedQueries({
#NamedQuery(name = "Timetable.findAll", query = "SELECT t FROM Timetable t"),
#NamedQuery(name = "Timetable.findByPeriod", query = "SELECT t FROM Timetable t WHERE t.timetablePK.period = :period"),
#NamedQuery(name = "Timetable.findByDay", query = "SELECT t FROM Timetable t WHERE t.timetablePK.day = :day"),
#NamedQuery(name = "Timetable.findByClassidClass", query = "SELECT t FROM Timetable t WHERE t.timetablePK.classidClass = :classidClass")})
public class Timetable implements Serializable {
private static final long serialVersionUID = 1L;
#EmbeddedId
protected TimetablePK timetablePK;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "timetable")
private Collection<Absence> absenceCollection;
#JoinColumn(name = "Class_idClass", referencedColumnName = "idClass", insertable = false, updatable = false)
#ManyToOne(optional = false)
private Class class1;
public Timetable() {
}
public Timetable(TimetablePK timetablePK) {
this.timetablePK = timetablePK;
}
TimetablePK
Embeddable
public class TimetablePK implements Serializable {
#Basic(optional = false)
#NotNull
#Column(name = "Period")
private int period;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 45)
#Column(name = "Day")
private String day;
#Basic(optional = false)
#NotNull
#Column(name = "Class_idClass")
private int classidClass;
public TimetablePK() {
}
public TimetablePK(int period, String day, int classidClass) {
this.period = period;
this.day = day;
this.classidClass = classidClass;
}
EDIT TWO
Your diagram indicates the TimeTable table has a primary key composed of three columns (Period, Day, and Class_idClass). You will need to add an annotation to Absence.timeTable that looks something like this:
public class Absence implements Serializable {
...
#JoinColumns[
#JoinColumn(name = "TimeTable_Period", referencedColumnName = "Period", ...),
#JoinColumn(name = "????", referencedColumnName = "Day", ...),
#JoinColumn(name = "Class_idClass", referencedColumnName = "Class_idClass", ...)
]
#ManyToOne(optional = false)
private TimeTable timeTable;
...
}
Consider this:
#JoinColumn(name = "TimeTable_Period", referencedColumnName = "Period")
private Timetable timetable;
You have referenced to the column Period at your Timetable entity. But in the Timetable.java I don't see any field that is mapped with your Period column of your table.
For example:
#Id // as its the primary key!
#Column(name="Period")
private Long period
This should be same for other referenced entities those you have used with your #ManyToOne mapping.