I have an issue with hibernate and postgres using spring boot.
When I run the application I see in postgres logs these errors(without any data bootstrap):
2021-06-25 13:55:31.057 UTC [81] ERROR: constraint "uk_j1xiaxeat9b5r1qs27ei0t2a6" of
relation "process_template_base_environmental_impact" does not exist
2021-06-25 13:55:31.057 UTC [81] STATEMENT: alter table
process_template_base_environmental_impact drop constraint
UK_j1xiaxeat9b5r1qs27ei0t2a6
2021-06-25 13:55:31.062 UTC [81] ERROR: constraint "uk_9568qjc94suvuskoi9o2li3er" of
relation "process_template_elementary_flow_template" does not exist
2021-06-25 13:55:31.062 UTC [81] STATEMENT: alter table
process_template_elementary_flow_template drop constraint
UK_9568qjc94suvuskoi9o2li3er
2021-06-25 13:55:31.064 UTC [81] ERROR: constraint "uk_dy1ej2j9qxeoq6ca641tpfxr5" of
relation "process_template_flow_template" does not exist
2021-06-25 13:55:31.064 UTC [81] STATEMENT: alter table
process_template_flow_template drop constraint UK_dy1ej2j9qxeoq6ca641tpfxr5
I have an entity called ProcessTemplate with ProcessTemplateId as compositeKey, and 3 cascades on ElementaryFlowTemplate, BaseEnvironmentalImpact, and FlowTemplate.
ProcessTemplate:
#Data
#Entity
#EqualsAndHashCode(onlyExplicitlyIncluded = true)
#Table(name = "process_template")
public class ProcessTemplate {
#EmbeddedId
#EqualsAndHashCode.Include
private ProcessTemplateId id;
#ManyToOne
#JoinColumn(name = "fk_process_base", referencedColumnName = "id")
private ProcessBase processBase;
#ManyToOne
#JoinColumn(name = "fk_reference_flow_base", referencedColumnName = "id")
private FlowBase referenceProduct;
#OneToMany(cascade = CascadeType.ALL)
private Set<BaseEnvironmentalImpact> baseEnvironmentalImpacts;
#OneToMany(cascade = CascadeType.ALL)
#OrderBy("impactsContribute DESC" )
private Set<FlowTemplate> flowsTemplate;
#OneToMany(cascade = CascadeType.ALL)
#OrderBy("impactsContribute DESC" )
private Set<ElementaryFlowTemplate> elementaryFlowsTemplate;
#ManyToOne
#JoinColumn(name = "fk_source_info", referencedColumnName = "id")
private SourceInfo sourceInfo;
#Column(name = "version")
#Version
private Long version;
}
ProcessTemplateId:
#Embeddable
public class ProcessTemplateId implements Serializable {
#Column(name = "process_base_id")
private UUID processBaseId;
#Column(name = "reference_product_id")
private UUID referenceProductId;
public ProcessTemplateId() {
}
public ProcessTemplateId(UUID processBaseId, UUID referenceProductId) {
this.processBaseId = processBaseId;
this.referenceProductId = referenceProductId;
}
public UUID getProcessBaseId() {
return processBaseId;
}
public UUID getReferenceProductId() {
return referenceProductId;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof ProcessTemplateId)) return false;
ProcessTemplateId that = (ProcessTemplateId) o;
return Objects.equals(getProcessBaseId(), that.getProcessBaseId()) &&
Objects.equals(getReferenceProductId(), that.getReferenceProductId());
}
#Override
public int hashCode() {
return Objects.hash(getProcessBaseId(), getReferenceProductId());
}
}
AbstractFlowTemplate:
#Data
#EqualsAndHashCode(onlyExplicitlyIncluded = true)
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class AbstractFlowTemplate {
#Id
#EqualsAndHashCode.Include
private String id;
#Enumerated(EnumType.STRING)
private FlowType flowType;
#ManyToOne
#JoinColumn(name = "fk_source_info", referencedColumnName = "id")
private SourceInfo sourceInfo;
#Column(name = "version")
#Version
private Long version;
}
ElementaryFlowTemplate:
#Data
#Entity
#EqualsAndHashCode(callSuper = true, onlyExplicitlyIncluded = true)
#Table(name = "elementary_flow_template")
public class ElementaryFlowTemplate extends AbstractFlowTemplate {
#ManyToOne
#JoinColumn(name = "fk_elementary_flow_base", referencedColumnName = "id")
private ElementaryFlowBase elementaryFlowBase;
}
FlowTemplate (linkedProcessTemplate is not the bidirectional relation to ProcessTemplate but another unidirectional relation, because each flowTemplate had a link to another ProcessTemplate):
#Data
#Entity
#EqualsAndHashCode(callSuper = true, onlyExplicitlyIncluded = true)
#Table(name = "flow_template")
public class FlowTemplate extends AbstractFlowTemplate {
#ManyToOne
#JoinColumn(name = "fk_flow_base", referencedColumnName = "id")
private FlowBase flowBase;
#ManyToOne(cascade = CascadeType.MERGE)
#JoinColumns({#JoinColumn(name = "process_base_id", referencedColumnName =
"process_base_id"),
#JoinColumn(name = "reference_product_id", referencedColumnName =
"reference_product_id")})
private ProcessTemplate linkedProcessTemplate;
}
BaseEnvironmentalImpact:
#Data
#Entity
#EqualsAndHashCode(onlyExplicitlyIncluded = true)
#Table(name = "base_environmental_impact")
public class BaseEnvironmentalImpact {
#Id
#EqualsAndHashCode.Include
private String id;
private double value;
#ManyToOne
#JoinColumn(name = "fk_methodology", referencedColumnName = "id")
private Methodology methodology;
#ManyToOne
#JoinColumn(name = "fk_impact_category", referencedColumnName = "id")
private ImpactCategory impactCategory;
#ManyToOne
#JoinColumn(name = "fk_impact_indicator", referencedColumnName = "id")
private ImpactIndicator impactIndicator;
#ManyToOne
#JoinColumn(name = "fk_source_info", referencedColumnName = "id")
private SourceInfo sourceInfo;
#Column(name = "version")
#Version
private Long version;
//ref
#ManyToOne
#JoinColumn(name = "fk_elementary_flow_base")
private ElementaryFlowBase elementaryFlowBase;
#ManyToOne
#JoinColumns({
#JoinColumn(
name = "process_base_id",
referencedColumnName = "process_base_id"),
#JoinColumn(
name = "reference_product_id",
referencedColumnName = "reference_product_id")
})
private ProcessTemplate processTemplate;
}
As I wrote I cannot understand why I had an errors log, probably I make a mistake in the relation or cascade but I'm not able to figure out the issue. If I import data they seem correctly inserted so I cannot understand the problem.
Thanks in advance for the help.
SOLVED, EDIT:
I solve only the error on ProcessTemplate-BaseEnvironmentalImpact adding a mappedBy.
I don't include a schema because I think it's autogenerated, I include these parameters in application properties:
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation = true
spring.jpa.hibernate.ddl-auto = create-drop
logging.level.org.hibernate = ERROR
spring.jpa.generate-ddl = true
I also solved other issues adding:
#JoinColumns({
#JoinColumn(name = "fk_pt_process_base_id", referencedColumnName = "process_base_id"),
#JoinColumn(name = "fk_pt_reference_product_id", referencedColumnName = "reference_product_id")
} )
Related
I have two entities, each one pointing to one single table in an postgres. The entities belong to an Spring/graddle/JPA/Hibernate web application.
#Entity
#Table(name = "STAFF")
#AttributeOverride(name = "id", column = #Column(name = "ID"))
public class StaffEntity extends AbstractEntity {
#Column(name = "NAME")
private String name;
#Column(name = "SHORT_NAME")
private String shortName;
#ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinColumn(name = "STAFF_GROUP_ID", referencedColumnName = "ID")
private StaffGroupEntity staffGroup;
/* More attributes, getters and setters */
#Entity
#Table(name = "STAFF_GROUP")
#AttributeOverride(name = "id", column = #Column(name = "ID"))
public class StaffGroupEntity extends AbstractEntity {
#Column(name = "NAME")
private String name;
#ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinColumn(name = "LEAD_ID", referencedColumnName = "ID")
private StaffEntity lead;
/* More attributes, getters and setters */
When i update with swagger the group with a lead that is already in the group i get a stackOverFlowError
java.lang.StackOverflowError: null
mapping with mapstruct
I have two java entity classes :
#Table(name = "user")
public class UserEntity
{
#Id
#Column(name = "id", unique = true, nullable = false)
private Long id;
#OneToOne(cascade = CascadeType.PERSIST, fetch = FetchType.EAGER)
#JoinColumn(name = "opportunity_id")
private OpportunityEntity opportunity;
}
and
#Table(name = "opportunity")
public class OpportunityEntity
{
#Id
#Column(name = "id", unique = true, nullable = false)
private Long id;
#OneToMany
#JoinColumn(name = "opportunity_id")
private List<UserEntity> users;
#OneToOne
#JoinColumn(name = "mainuser_id")
private UserEntity mainUser;
}
When i search for a list of Users [find users], i've got a "stackoverflow" when mapping User.opportunity.
the bug was clear that the opportunity.mainUser refer to User which itself refer to the same opportunity.
Is there another way to design my models ?
For example create a boolean isMain in User Model ?
Try to specify relationship to UserEntity by adding mappedBy to annotatation
#Table(name = "opportunity")
public class OpportunityEntity
{
#Id
#Column(name = "id", unique = true, nullable = false)
private Long id;
#OneToMany
#JoinColumn(name = "opportunity_id")
private List<UserEntity> users;
#OneToOne(mappedBy="opportunity")
#JoinColumn(name = "mainuser_id")
private UserEntity mainUser;
}
I have 3 tables as #Entity, and 2 join tables in my spring + hibernate app.
In one of join table i have extra column. I want to take info from this info column when i take info from my main table.
Main table code:
#Entity
#Table(name = "items")
public class Items {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private int id;
#Column(name = "name")
private String name;
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "crafts"
,joinColumns = #JoinColumn(name = "item_id")
,inverseJoinColumns = #JoinColumn(name = "plot_id"))
private Set<Plots> plotInfo = new HashSet<>();
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "item_materials"
,joinColumns = #JoinColumn(name = "item_id")
,inverseJoinColumns = #JoinColumn(name = "material_id"))
private Set<Materials> materialsInfo = new HashSet<>();
Table item_materials have this columns "id, item_id(fkey), material_id(fkey), expense" and one of this which names as "expense" i need to have in my final result.
How can i code my class to have "expense" in my result?
I read about #embeddable but still dont understand how to use in my project.
Don't use a #ManyToMany association. Map the join table as entity and model it similar to this:
#Entity
#Table(name = "items")
public class Items {
#OneToMany(mappedBy = "item")
private Set<Crafts> plotInfo = new HashSet<>();
}
#Entity
#Table(name = "plots")
public class Plots {
#OneToMany(mappedBy = "plot")
private Set<Crafts> items = new HashSet<>();
}
#Entity
#Table(name = "crafts")
public class Crafts {
#EmbeddedId
private CraftsId id;
#ManyToOne
#JoinColumn(name = "item_id", insertable = false, updatable = false)
private Items item;
#ManyToOne
#JoinColumn(name = "plot_id", insertable = false, updatable = false)
private Plots plot;
}
#Embeddable
public class CraftsId {
#Column(name = "item_id")
private Integer itemId;
#Column(name = "plot_id")
private Integer plotId;
// equals + hashCode
}
I'm trying to build a oneToMany relation between a Rent table and a RentAgreement table, the rent table has a composite key rentKey
#Setter
#Getter
#Entity
#Table(name = "Rent")
public class Rent {
#EmbeddedId
#Column(name = "rentKey")
private RentKey rentKey;
#OneToMany(mappedBy="rent", cascade = {CascadeType.REFRESH, CascadeType.REMOVE})
#JsonIgnoreProperties(value = "rent", allowSetters=true)
private Set<RentalAgreement> rentalAgreements;
...
The RentKey is
#Data
#Setter
#Getter
#Embeddable
public class RentKey implements Serializable{
private String rentStartDate;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "agent_id", referencedColumnName = "id")
#JsonIgnoreProperties(value = "rents", allowSetters=true)
private Agent agent;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "client_id", referencedColumnName = "id")
#JsonIgnoreProperties(value = "rents", allowSetters=true)
private Client client;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "propertyRent_id", referencedColumnName = "id")
#JsonIgnoreProperties(value = "rents", allowSetters=true)
private PropertyRent propertyRent;
...
and the RentAgreement is
#Data
#Entity
#Table(name = "RentalAgreement")
public class RentalAgreement {
#Id
#GeneratedValue
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumns({
#JoinColumn(name="agent_id", referencedColumnName="agent_id"),
#JoinColumn(name="client_id", referencedColumnName="client_id"),
#JoinColumn(name="propertyRent_id", referencedColumnName="propertyRent_id")
})
#JsonIgnoreProperties(value = "rentalAgreements", allowSetters=true)
private Rent rent;
...
When I run the code, I get
org.hibernate.AnnotationException: referencedColumnNames(agent_id, client_id, propertyRent_id) of com.mikason.PropView.dataaccess.documentEntity.RentalAgreement.rent referencing com.mikason.PropView.dataaccess.commercialEntity.Rent not mapped to a single property
Could anyone tell me where I did wrong?
Thanks
I have tried to create some JPA Entities for a DB designed with the following tables: PRINCIPALS and CREDENTIALS which have the following relations with other tables:
#Entity
#Table(name = "CREDENTIALS")
public class Credentials {
#Id
#Column(name = "CREDENTIAL_ID")
private Integer credentialID;
#Id
#Column(name = "CREDENTIAL_TYPE_ID")
private String credentialTypeID;
#OneToOne
#JoinColumn(name = "CREDENTIAL_TYPE_ID", insertable = false, updatable = false)
private CredentialTypes credentialTypes;
}
CREDENTIALS has a oneToOne relation with CREDENTIAL_TYPES
#Entity
#Table(name = "CREDENTIAL_TYPES")
public class CredentialTypes {
#Id
#Column(name = "CREDENTIAL_TYPE_ID")
private String credentialTypeID;
#Column(name = "DESCRIPTION")
private String description;
}
#Entity
#Table(name = "PRINCIPALS")
public class Principals implements Serializable {
#Id
#Column(name = "PRINCIPAL_TYPE_ID", nullable = false)
private String principalTypeID;
#Column(name = "PRINCIPAL_ID", nullable = false)
private String principalID;
#OneToOne
#JoinColumn(name = "PRINCIPAL_TYPE_ID", insertable = false, updatable = false)
private PrincipalTypes principalTypes;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinTable(name = "PRINCIPAL_CREDENTIAL",
joinColumns = #JoinColumn(name = "CREDENTIAL_ID"),
inverseJoinColumns = #JoinColumn(name = "PRINCIPAL_ID"))
private List<Credentials> credentials;
PRINCIPALS has a oneToOne relation with PRINCIPAL_TYPES
#Entity
#Table(name = "PRINCIPAL_TYPES")
public class PrincipalTypes implements Serializable {
#Id
#Column(name = "PRINCIPAL_TYPE_ID", nullable = false)
private String principalTypeID;
#Column(name = "DESCRIPTION")
private String description;
And finally PRINCIPALS has a oneToMany relation with CREDENTIALS and uses a join table PRINCIPLE_CREDENTIAL
#Entity
#Table(name = "PRINCIPAL_CREDENTIAL")
public class PrincipalCredential implements Serializable {
#Id
#Column(name = "PRINCIPAL_TYPE_ID", nullable = false)
private String principalTypeID;
#Id
#Column(name = "PRINCIPAL_ID", nullable = false)
private String principalID;
#Id
#Column(name = "CREDENTIAL_ID")
private Integer credentialID;
#Id
#Column(name = "CREDENTIAL_TYPE_ID")
private String credentialTypeID;
At startup (using SpringBoot) I receive an error for the oneToMany relation between Principals and Credentials and just don't have any idea how to fix it... Tried various other methods (The DB design cannot be changed).
Caused by: org.hibernate.AnnotationException: A Foreign key refering entities.Principals from entities.Credentials has the wrong number of column. should be 2
at org.hibernate.cfg.annotations.TableBinder.bindFk(TableBinder.java:502)
at org.hibernate.cfg.annotations.CollectionBinder.bindCollectionSecondPass(CollectionBinder.java:1467)
at org.hibernate.cfg.annotations.CollectionBinder.bindManyToManySecondPass(CollectionBinder.java:1233)
at org.hibernate.cfg.annotations.CollectionBinder.bindStarToManySecondPass(CollectionBinder.java:794)
at org.hibernate.cfg.annotations.CollectionBinder$1.secondPass(CollectionBinder.java:729)
at org.hibernate.cfg.CollectionSecondPass.doSecondPass(CollectionSecondPass.java:70)
at org.hibernate.cfg.Configuration.originalSecondPassCompile(Configuration.java:1697)
at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1426)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1846)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:85
I find the exception wierd because there is no refering of Principlas from Credentials....
PRINCIPLE_TYPE_ID and CREDENTIAL_TYPE_ID are missing in the joinColumns/inverseJoinColumns. I think you must use the #JoinColumns Annotation