I trying to map my class to database,the class reference to itself by "id_comment_parent", but when running a test, I get the following error:
Caused by: org.hibernate.AnnotationException: A Foreign key refering com.ecommerce.entities.Comment from com.ecommerce.entities.Comment has the wrong number of column. should be 2
at org.hibernate.cfg.annotations.TableBinder.bindFk(TableBinder.java:646) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final]
at org.hibernate.cfg.ToOneFkSecondPass.doSecondPass(ToOneFkSecondPass.java:102) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final]
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processEndOfQueue(InFlightMetadataCollectorImpl.java:1814) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final]
these is my classe:
#Entity
#Table(name = "comment", catalog = "Ecommerce_db")
public class Comment implements Serializable {
#EmbeddedId
#AttributeOverrides({
#AttributeOverride(name = "idComment", column = #Column(name = "id_comment", nullable = false)),
#AttributeOverride(name = "idCommentParent", column = #Column(name = "id_comment_parent", nullable = false)) })
private CommentId id;
#Column(name = "id_user", nullable = false)
private long idUser;
#Column(name = "comment", length = 65535)
private String comment_1;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "id_comment_parent", nullable = false, insertable = false, updatable = false)
private Comment comment;
}
anyone have any idea?
Looks like CommentId that represents de Primary Key of Commenthas more that one column. So the ForeignKey must have more than one JoinColumn too.
Besides, it seems that you are mixing the fields of your primary key and your foreign key, as you have id_comment_parent in both primary key and foreign key.
You actually have comment entities with the same id_comment but with different id_comment_parent? It that's not the case, I think that a more coherent mapping would be that id_comment is the primary key, and id_comment_parent is the foreing key. Something like this:
#Entity
#Table(name = "comment", catalog = "Ecommerce_db")
public class Comment implements Serializable {
#Id
#Column(name = "id_comment", nullable = false)
private Long id;
#Column(name = "id_user", nullable = false)
private long idUser;
#Column(name = "comment", length = 65535)
private String comment_1;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "id_comment_parent")
private Comment parent;
}
Related
the problems is when #ManyToOne make a #Joincolumn ID_REPORT (it´s a primary key ) and #Joincolumn ID_TEMPLATE_DEFAULT
Repeated column in mapping for entity: CurReport column: id_report (should be mapped with insert="false" update="false")
Code
First table CUR_TEMPLATE
CREATE TABLE CUR_TEMPLATE
(
ID_REPORT NUMBER(5,0) NOT NULL,
ID_TEMPLATE NUMBER(5,0) NOT NULL,
-- Other fields
);
ALTER TABLE CUR_TEMPLATE ADD CONSTRAINT PK_CUR_TEMPLATE PRIMARY KEY (ID_REPORT, ID_TEMPLATE)
-- CUR_TEMPLATE foreign keys
ALTER TABLE CUR_TEMPLATE ADD CONSTRAINT FK_CUR_PLAN_REFERENCE_CUR_REPO FOREIGN KEY (ID_REPORT)
REFERENCES CUR_REPORTS (ID_REPORT);
Second table CUR_REPORTS
-- CUR_REPORTS definition
CREATE TABLE CUR_REPORTS
(
ID_REPORT NUMBER(3,0) NOT NULL,
NAME_REPORT VARCHAR2(100) NOT NULL,
-- other fields
ID_TEMPLATE_DEFAULT NUMBER(5,0),
-- other fields
) ;
ALTER TABLE CUR_REPORTS ADD CONSTRAINT PK_CUR_REPORTS PRIMARY KEY (ID_REPORT)
ALTER TABLE CUR_REPORTS CONSTRAINT FK_CUR_REPO_REFERENCE_CUR_PLAN FOREIGN KEY (ID_REPORT, ID_TEMPLATE_DEFAULT)
REFERENCES CUR_TEMPLATE (ID_REPORT, ID_TEMPLATE)
First table CUR_REPORTS Entity CurReport
#Entity
#Table(name = "CUR_REPORTS")
#IdClass(CurPlantillaPK.class)
#Getter
#Setter
public class CurReport {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID_REPORT", nullable = false)
private Long id;
#Column(name = "NAME_REPORT", nullable = false, length = 100)
private String nombreReporte;
#ManyToOne(fetch = FetchType.LAZY) <---WHERE IS THE PROBLEM
#JoinColumn(name = "ID_REPORT", referencedColumnName = "ID_REPORTE")
#JoinColumn(name = "ID_TEMPLATE_DEFAULT", referencedColumnName = "ID_TEMPLATE")
private CurTemplate curTemplate;
#OneToMany(mappedBy = "curReport")
private Set<CurTemplate> curTemplates= new LinkedHashSet<>();
}
Second table CUR_TEMPLATE Entity CurReport
#Entity
#Table(name = "CUR_TEMPLATE")
#IdClass(CurPlantillaPK.class)
#Getter
#Setter
public class CurTemplate {
#Id
#Column(name = "ID_REPORT", nullable = false)
private Long idReport;
#Id
#Column(name = "ID_TEMPLATE", nullable = false)
private Long idTemplate;
#ManyToOne(optional = false, fetch = FetchType.LAZY)
#JoinColumn(name = "ID_REPORT", foreignKey = #ForeignKey(name = "FK_CUR_PLAN_REFERENCE_CUR_REPO"), referencedColumnName = "ID_REPORT", insertable = false, updatable = false)
private CurReport curReport;
}
When i add insertable=false, updatable=false
#JoinColumn(name = "ID_REPORT", referencedColumnName = "ID_REPORT", insertable=false, updatable=false)
said
Mixing insertable and non insertable columns in a property is not allowed: CurTemplate
How could i map those relationships?
How resolve the #JoinColumn when one field of the FK are column PK?
You can use a derived identity and map CurTemplate like this:
#Entity
#Table(name = "CUR_TEMPLATE")
#IdClass(CurTemplatePK.class)
#Getter
#Setter
public class CurTemplate {
#Id
#Column(name = "ID_TEMPLATE", nullable = false)
private Long idTemplate;
#Id
#ManyToOne(optional = false, fetch = FetchType.LAZY)
#JoinColumn(name = "ID_REPORT", foreignKey = #ForeignKey(name = "FK_CUR_PLAN_REFERENCE_CUR_REPO"), referencedColumnName = "ID_REPORT", insertable = false, updatable = false)
private CurReport curReport;
}
Then you will need an #IdClass like this:
public class CurTemplatePK {
Long idTemplate; // matches name of #Id attribute
Long curReport; // matches name of #Id attribute and type of CurReport PK
}
Then you should use a basic mapping for the default template key and provide a getter for the default template object:
#Entity
#Table(name = "CUR_REPORTS")
#IdClass(CurPlantillaPK.class)
#Getter
#Setter
public class CurReport {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID_REPORT", nullable = false)
private Long id;
#Column(name = "NAME_REPORT", nullable = false, length = 100)
private String nombreReporte;
#Column(name = "ID_TEMPLATE_DEFAULT")
private Long idDefaultTemplate;
#OneToMany(mappedBy = "curReport")
private Set<CurTemplate> curTemplates= new LinkedHashSet<>();
public CurTemplate getDefaultTemplate() {
return this.curTemplates.stream()
.filter(template -> template.getIdTemplate().equals(idDefaultTemplate))
.findFirst()
.orElse(null);
{
}
If you want to allow clients to set the default template, you will need to implement a setter that first verifies that the new default template is already in the set curTemplates.
I want to join a single column from another table to one of my #Entity classes:
Currently it works as follows:
#Entity
public class Product {
#Id
private long id; //autogenerated
String type; //used for mapping
#ManyToOne
#JoinColumn(name = "type", insertable = false, updatable = false)
ProductMapping mapping;
}
#Entity
public class ProductMapping {
#Id
String type;
String longname;
}
Question: how could I replace the #ManyToOne mapping to directly map to String longname?
//TODO: how to directly map to 'mapping.longname'?
#JoinColumn(name = "type", insertable = false, updatable = false)
String mapping.longname;
You can use #Formula annotation with a query like this :
#Formula("(select pm.longname from product_mapping pm where pm.COL_NAME = value)")
private String longName;
//give the column name of type from product_mapping table
OR
You can also use the below approach :
#ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name = "type", referencedColumnName = "COL_NAME", insertable = false, updatable = false)
ProductMapping mapping;
The other entity use #NaturalId annotation on the field.
#Entity
public class ProductMapping {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID")
String type;
#NaturalId
#Column(name = "SOME_VALUE")
String longname;
}
I used question_id as the primary key of questions table and it is a foreign key for the answers table. #JoinColumn has used for declare referencedColumnName .
#Entity
#Table(name = "questions")
public class Question {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long question_id;
#Column(nullable = false, unique = false, length = 100)
private String question_subjectArea;
#Column(nullable = false, unique = false, length = 1000)
private String fullQuestion;
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn( name = "questionID", referencedColumnName = "question_id")
List<Answer> answer = new ArrayList<>();
//Getters and setters
#Entity
#Table(name = "answers")
public class Answer {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long answer_id;
#Column(nullable = true, unique = false, length = 100)
private Long answer_authorID;
#Column(nullable = false, unique = false, length = 100)
private String fullAnswer;
//Getters and setters
Application.properties configuration as follows
spring.jpa.hibernate.ddl-auto=create
In our Entity class: Answer, seems you need also define the member: Question.
#ManyToOne
#JsonIgnore
#JoinColumn(name = "question", referencedColumnName = "question_id")
private Question question;
I'm having an issue with JPA and Hibernate. I have 2 classes (actually more but those are the 2 that are giving me a headache).
They have a OneToMany/ManyToOne relationship, and I have specified on the OneToMany that I want it to cascade every possible change (CascadeType.ALL).
However, when I let HBM2DDL run in "update" mode, it is creating foreign key constraints that are not fitting what I want to achieve. It is creating a constraint in RESTRICT mode, which is absolutely not what I have specified. Perhaps the error is in my code ? I've joined it below.
#Entity
public class Department {
#Id
#Column(name = "id", nullable = false)
private int id;
#Column(name = "name", nullable = false)
private String name;
#OneToMany(mappedBy = "departmentByDepartment", cascade = CascadeType.ALL)
private Collection<Article> productsById;
#OneToMany(mappedBy = "departmentByDepartment", cascade = CascadeType.ALL)
private Collection<User> usersById;
And then :
#Entity
#Table(name = "product", schema = "qlog_project", catalog = "")
public class Article {
#Id
#Column(name = "id", nullable = false)
private int id;
#Column(name = "name", nullable = false)
private String name;
#Column(name = "description", nullable = false)
private String description;
#Column(name = "price", nullable = false)
private double price;
#Column(name = "image", nullable = false)
private String image;
#ManyToOne
#JoinColumn(name = "department", referencedColumnName = "id", nullable = false)
private Department departmentByDepartment;
#OneToMany(mappedBy = "productByProductId", cascade = CascadeType.ALL)
private Collection<Stock> stocksById;
Also, I cannot seem to be able to delete an Article instance with EntityManager.remove(). It's not producing any query and not doing anything. Maybe it is linked ?
Thanks in advance,
Regards
I have the following model that I need to annotate using JPA:
Merchant(merchant_id, ...).
MerchantType(id1, id2, ...)
MerchantMerchantTypeAssociationTable(merchant_id, id1, id2)
I cannot figure out how to map the association table. Mapping Merchant is straitghtforward, so I will leave it outside of the mappings. The other mappings are as follows:
MerchantType:
#Entity
class MerchantType {
#EmbeddedId
#AttributeOverrides({
#AttributeOverride(name = "e1_id", column=#Column(name="e1_id")),
#AttributeOverride(name = "another_id", column=#Column(name="another_id"))
})
MerchantTypePk id;
#ManyToOne
#JoinColumn(name = "e1_id", referencedColumnName = "e1_id", insertable = false, nullable = false)
#MapsId("e1_id")
AnotherEntity1 e1;
#Column(name = "another_id", referencedColumnName = "another_id", insertable = false, nullable = false)
Long anotherId;
//Two other local fields irrelevant to the discussion here
public MerchantType(){
this.id = new MerchantTypePk();
}
//Getters and setters here.
}
//MerchantTypePk is a simple Embeddable class here below with two Long fields:
//e1_id and another_id
MerchantMerchantTypeAssociation:
#Entity
class MerchantMerchantTypeAssociation {
#EmbeddedId
#AttributeOverrides({
#AttributeOverride(name = "e1_id", column = #Column(name = "e1_id")),
#AttributeOverride(name = "another_id", column = #Column(name = "another_id"))
#AttributeOverride(name = "offer_id", column = #Column(name = "merchant_id"))
})
private MerchantMerchantTypeAssociationPk id;
//******** HERE IS THE QUESTION
//******** HERE IS THE QUESTION
//******** HERE IS THE QUESTION
#ManyToOne
#JoinColumns({
#JoinColumn(name = "e1_id", referencedColumnName = "e1_id", insertable = false, updatable = false),
#JoinColumn(name = "another_id", referencedColumnName = "another_id", insertable = false, updatable = false)
})
#MapsId("e1_id")
#MapsId("another_id")
private MerchantType merchantType;
//Similar mapping to the one above, but with only one Join Column
private Merchant merchant;
//One more local field that is irrelevant to the mapping
//but is the one that is forcing me to map a many - to - many relationship
//in this way.
}
//MerchantMerchantTypeAssociationPk as a simple embeddable
Question: How can I make a mapping for this kind of entities when the annotation '#MapsId' cannot be repeated and it does not accept more than one value?
You did not include the code for MerchantMerchantTypeAssociationPk, but I'm guessing it looks like this:
#Embeddable
public class MerchantMerchantTypeAssociationPk {
public MerchantPk merchantPK;
public MerchantTypePk merchantTypePK;
}
#MapsId is used to specify the attribute within the composite key to which the relationship attribute corresponds, not the columns. So MerchantMerchantTypeAssociation should look like this:
#Entity class MerchantMerchantTypeAssociation {
#EmbeddedId
private MerchantMerchantTypeAssociationPk id;
#ManyToOne
#JoinColumns({
#JoinColumn(name = "e1_id", referencedColumnName = "e1_id",...),
#JoinColumn(name = "e2_id", referencedColumnName = "e2_id",...)
})
#MapsId("merchantTypePK") // <<< *attribute* in Embeddable
private MerchantType merchantType;
#ManyToOne
#JoinColumn(name = "m_id", referencedColumnName = "merchant_id",...)
#MapsId("merchantPK") // <<< *attribute* in Embeddable
private Merchant merchant;
}
Derived identities are discussed in the JPA 2.1 spec, section 2.4.1.