Unable to create unique key constraint - Make sure that you use the correct column name which depends on the naming strategy in use - spring-data-jpa

The full error message is:
Unable to create unique key constraint (aircraft_series_id, service_enum) on table aircraft_service: database column 'service_enum' not found. Make sure that you use the correct column name which depends on the naming strategy in use (it may not be the same as the property name in the entity, especially for relational types)
My entity is specified as:
#Entity
#Table(uniqueConstraints = { #UniqueConstraint(columnNames = { "aircraft_series_id", "service_enum" }) })
#Getter
#Setter
#NoArgsConstructor
#ToString
public class AircraftService {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#NotNull
private Integer minimumQuantity;
#NotNull
private Integer maximumQuantity;
#NotNull
private Integer defaultQuantity;
#NotNull
#ManyToOne(optional = false)
#JsonIgnore
private AircraftSeries aircraftSeries;
#NotNull
#Enumerated(EnumType.STRING)
private ServiceEnum serviceEnum;
}
If I comment out the #Table(uniqueConstraints = { #UniqueConstraint(columnNames = { "aircraft_series_id", "service_enum" }) }) annotation then the columns are created and I can see the field names when opening the table under the SQL client.
service_enum
aircraft_series_id
For now I'm running the application against the H2 database.

I could have the application running not throw an exception if the class is boasting the column annotations, as in:
#Column(name = "service_enum")
#ManyToOne(optional = false)
#JoinColumn(name = "service_profile_id")
I don't see why this is the case, as by default, the column names are exactly the same, when attributed by the application itself.

Related

Relation XX does not exist; could not extract Resultset error while using a view convertHibernateAccessException

I am using a view in my entity class. Although the view-column mappings are exactly the same as in entity class, I am receiving the exception "ERROR: relation "location_view" does not exist - Position: 15 - underlying exception is SQLGrammarException could not extract ResultSet at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:261)"
When I replace the view to the underlying SQL query, it works in SpringBoot. Can you please let me know where I am going wrong?
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#Data
#ToString
#Entity
#Table(name = "location_view")
public class Location{
#Id
#Column(name = "id")
long id;
#Column(name = "name")
String name;
#Column(name = "total")
long total;
#Column(name = "created_by")
long createdBy;
#Column(name = "created_on")
Timestamp createdOn;
}
public interface LocationDAO extends JpaRepository<Location, Long> {
#Query(value = "select * from location_view", nativeQuery = true)
List<Location> getLocations();
}
In my controller, I am making call to locationDAO.getLocations();
Probably the table/view is in a different schema? Or maybe the user for the JDBC connection has no permission to read from that table/view?

How to reference a Composite Secondary Key

The below examples show what I tried to reference an entity by a unique combination of columns that is not its primary key.
I want to do it that way because the referencing table contains all the necessary constituents of the referenced "Composite Secondary Key" but it does not contain the Primary Key.
How can I achieve this? (If possible without being Hibernate specific)
Base example
Suppose an entity has a primary key as well as a composite secondary key:
#Entity
#Table(name = "EXAMPLE_DATA",
uniqueConstraints = {
#UniqueConstraint(columnNames = {
"COMPOSITE_KEY_PART_1",
"COMPOSITE_KEY_PART_2"})
})
public class ExampleData {
#Id
#Column
private Long exampleDataId;
#Column(name = "COMPOSITE_KEY_PART_1")
private String compositeKeyPart1;
#Column(name = "COMPOSITE_KEY_PART_2")
private String compositeKeyPart2;
}
I would like to reference it from another table by its composite secondary key:
#Entity
#Table(name = "EXAMPLE")
public class Example {
#Id
#Column
private Long exampleId;
#Column(name = "COMPOSITE_KEY_PART_1")
private String compositeKeyPart1; // of ExampleData
#Column(name = "COMPOSITE_KEY_PART_2")
private String compositeKeyPart2; // of ExampleData
#MayToOne
#JoinColumn(name = "COMPOSITE_KEY_PART_1", insertable = false, updatable = false)
#JoinColumn(name = "COMPOSITE_KEY_PART_2", insertable = false, updatable = false)
private ExampleData exampleData;
}
However, this leads to
org.hibernate.AnnotationException:
A Foreign key refering com.example.ExampleData from com.example.Example has the wrong number of column. should be 1
Making a separate #Embeddable composite key
I tried making the secondary key embeddable
#Embeddable
public class CompositeKey implements Serializable {
#Column(name = "COMPOSITE_KEY_PART_1")
private String compositeKeyPart1;
#Column(name = "COMPOSITE_KEY_PART_2")
private String compositeKeyPart2;
}
and using it as an embedded object:
#Entity
#Table(name = "EXAMPLE_DATA",
uniqueConstraints = {
#UniqueConstraint(columnNames = {
"COMPOSITE_KEY_PART_1",
"COMPOSITE_KEY_PART_2"})
})
public class ExampleData {
#Id
#Column
private Long exampleDataId;
#Embedded
private CompositeKey compositeKey;
}
but that leads to the same exception:
org.hibernate.AnnotationException:
A Foreign key refering com.example.ExampleData from com.example.Example has the wrong number of column. should be 1
Using #EmbeddedId
Using #EmbeddedId instead of just #Embedded leads to issues with multiple keys
org.hibernate.AnnotationException:
com.example.CompositeKey must not have #Id properties when used as an #EmbeddedId: com.example.ExampleData.compositeKey
Having only a single key works but is undesirable
The only way I can actually make it work is by removing the primary key and making the composite key the primary key (but I don't want that)
#Entity
#Table(name = "EXAMPLE_DATA")
public class ExampleData {
// #Id // removing this primary key is undesirable
#Column
private Long exampleDataId;
#EmbeddedId // This now becomes the primary key
private CompositeKey compositeKey;
}

ERROR: update or delete on table "tablename" violates foreign key constraint

I'm trying to delete the parent student or parent course and I get this error:
Caused by: org.postgresql.util.PSQLException: ERROR: update or delete on table "student" violates foreign key constraint "fkeyvuofq5vwdylcf78jar3mxol" on table "registration"
RegistrationId class is a composite key used in Registration class. I'm using Spring data jpa and spring boot.
What am I doing wrong? I know that putting cascadetype.all should also remove the children when the parent is deleted but it is giving me an error instead.
#Embeddable
public class RegistrationId implements Serializable {
#JsonIgnoreProperties("notifications")
#OneToOne(cascade=CascadeType.ALL)
#JoinColumn(name = "student_pcn", referencedColumnName="pcn")
private Student student;
#JsonIgnoreProperties({"teachers", "states", "reviews"})
#OneToOne(cascade=CascadeType.ALL)
#JoinColumn(name = "course_code", referencedColumnName="code")
private Course course;
Registration class
#Entity(name = "Registration")
#Table(name = "registration")
public class Registration {
#EmbeddedId
private RegistrationId id;
When you're using a relational DB, you are setting entities with relationships between these entities.
The error that you're getting means that:
You're trying to delete a record that its primary key is functioning as a foreign key in another table, thus you can't delete it.
In order to delete that record, first, delete the record with the foreign key, and then delete the original that you wanted to delete.
I made it work by using hibernate #OnDelete annotation. Some how the JPA.persistence CascadeTypes were not working. They had no effect for whichever I chose.
Just like below. Now I can remove the parent Student or the parent Course and all children(Registrations) are deleted with them.
#Embeddable
public class RegistrationId implements Serializable {
#JsonIgnoreProperties("notifications")
#OnDelete(action = OnDeleteAction.CASCADE)
#OneToOne
#JoinColumn(name = "student_pcn", referencedColumnName="pcn")
private Student student;
#JsonIgnoreProperties({"teachers", "states", "reviews"})
#OnDelete(action = OnDeleteAction.CASCADE)
#OneToOne
#JoinColumn(name = "course_code", referencedColumnName="code")
private Course course;
Foreign keys guarantee that an entry will exist in another table. This is a way of ensuring data integrity. SQL will never allow you to delete this entry while it still deletes in the other table. Either (1) this is letting you know you would have made a grave mistake by deleting this thing which is required or (2) you would like to put in a cascading delete so that not only is this entry deleted but so is what is supposed to be referencing it in the other table. Information on cascading deletes can be found here and written fairly easily (https://www.techonthenet.com/sql_server/foreign_keys/foreign_delete.php). If neither of these two descriptions fits you, evaluate why your foreign key relationship exists in the first place because it probably should not.
Try this method too. I got the answer with this method,This is just a test to remove.
Pay attention to the cascade!
MyUser Entity
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String firstname;
private String lastname;
private String mobile;
#Column(unique = true)
private String email;
private Long date;
private LocalTime localiime;
private LocalTime localiimeend;
#ManyToOne(fetch = FetchType.LAZY,cascade = CascadeType.MERGE)
#JoinColumn(foreignKey = #ForeignKey(name = "role_fk"))
private Role role;
Role Entity
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String description;
#OneToMany(mappedBy = "role", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private List<MyUser> users;
#ManyToOne (fetch = FetchType.LAZY,cascade = CascadeType.MERGE)
#JoinColumn(foreignKey = #ForeignKey(name = "rolecat_fk"))
private rolecat rolecat;
rolecat Entity
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
#OneToMany(mappedBy = "rolecat", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private List<Role> roles;

How to show 2 different type of mappings between 2 entity classes, holding each other's reference

The mappings between the 2 tables(Department and Employee) is as follows (Link for the image showing mapping is also provided):
Every department has one and only one department head.
Every department can have more than one employee.
dept_id and empId are primary keys of their respective tables.
dept_head(It is the Employee Id) and dept are foreign keys of their
respective tables.
Mapping Employee and Department table
I created entity classes for the above 2 tables (The structure is provided below).
Employee Class:
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "empId")
private Integer empId;
#Size(max = 45)
#Column(name = "name")
private String name;
#Size(max = 45)
#Column(name = "address")
private String address;
#Size(max = 45)
#Column(name = "grade")
private String grade;
#Size(max = 45)
#Column(name = "email")
private String email;
#JoinColumn(name = "dept", referencedColumnName = "dept_id")
#ManyToOne
private Department deptartment;
.. ...
}
Department class:
public class Department implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 8)
#Column(name = "dept_id")
private String deptId;
#Size(max = 45)
#Column(name = "name")
private String name;
#JoinColumn(name = "dept_head", referencedColumnName = "empId")
#OneToOne
private Employee deptHead;
#OneToMany(mappedBy = "deptartment")
private List<Employee> employeeList;
....
...
}
If I am adding mappedBy in Employee Class (like I did in Department), to show OneToOne mapping between empId and deptHead,the code is compiling and running. However, If I do not add the mappedBy statement in Employee class, as the above code shows, the code still compiles and runs fine.
I would want to know why the code above works even if I am not providing mappedBy in employee class.
If anybody can help me clearing the above doubts and explaining the logic behind its working would be great as I am new to this.
It is not quite clear where you tried to user it with and without the mappedBy attribute.
But if I get your question correctly, you ask why you can have only one or both sides annotated?
It depends on which side is the source and destination of your relation or wheter it's bi-directional. On the Java-side you can have a relation always in both directions due to object references, but on the Database-side, you might only have it in one direction.
Check out JPA Wiki book on that topic for more details.
Additionally, the API doc for OneToOne states:
Specifies a single-valued association to another entity that has
one-to-one multiplicity. It is not normally necessary to specify the
associated target entity explicitly since it can usually be inferred
from the type of the object being referenced. If the relationship is
bidirectional, the non-owning side must use the mappedBy element of
the OneToOne annotation to specify the relationship field or property
of the owning side.

JPA -- Using the one-to-one dependency relationship on insertion

I have 2 entity classes with one-to-one dependencies on their primary keys:
The primary table:
#Entity
#Table(name = "tablePrimary")
#XmlRootElement
//...
public class TablePrimary implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "id")
private Integer id;
#Basic(optional = false)
#Column(name = "code")
private String code;
// set the dependency of table2 to this class
#OneToOne(cascade = CascadeType.ALL)
#PrimaryKeyJoinColumn
private Table2 table2inst;
// ...
} // end of class TablePrimary
The dependent table:
#Entity
#Table(name = "table2")
#XmlRootElement
//...
public class Table2 implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Basic(optional = false)
#Column(name = "id")
private Integer id;
#Basic(optional = false)
#Column(name = "name")
private String name;
#MapsId
#OneToOne(mappedBy = "table2inst")
#JoinColumn(name = "id")
private TablePrimary tablePrimaryInst;
//...
} // end of class Table2
Whenever there is a row with say, id==55 in TablePrimary, there is
a row with the same id==55 in Table2 and vice-versa.
So in essence, these two tables are one table in logical level-- split into 2 physical tables for practicality.
When i'm inserting a row into the "logical" table,
i first am inserting to TablePrimary-- the primary table in the relationship,
getting the value of id==55 field of this new row i just inserted and inserting a row to
Table2 with that id value.
As part of this, i'm checking, just in case,
whether a row with id==55 is already in Table2.
Is there a better way of doing this?
Does JPA have a feature to make these two insertions to these two physical tables
by using the 1-1 dependency I configured on them-- without me having to do it "manually" in the code? Or a control feature on the id fields of the tables I set the dependency on?
If there is-- how is done? how does it handle the key value collision in the dependent table-- Table2?
A similar thing will come up on deletion. However, i'm not there yet, and might figure out out of this.
TIA.
You can take advantage of JPA cascading. You will have to define a cascade on the owning side (the one with the join column). If you have set the owning side of the relationship and persist the owning side, the inverse side will be persisted as well:
TablePrimary tp = new TablePrimary();
Table2 t2 = new Table2();
t2.setTablePrimaryInst(tp);
entityManager.persist(t2);
The 'mappedBy' element is supposed to be placed on the inverse side. You entities could look like this:
public class Table2 ...
#OneToOne(cascade=CascadeType.ALL)
#JoinColumn(name = "tp_id")
private TablePrimary tablePrimary;
public class TablePrimary...
#OneToOne(mappedBy="tablePrimary")
private Table2 table2;