I have an entity Mealplan, where each weekday (enum) contains a meal. This is realised with a map and a Many-to-Many relation like this:
#Entity
public class Mealplan {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#ManyToMany
#SortNatural
private Map<Weekday, Meal> mealsPerWeek;
(...)
}
This means, in my database the mealsPerWeek property is stored in an extra table. "mealplan_meals_per_week". This table contains the mealplan_id, the meal_per_week_id (mealID) and the weekday_id.
Now, if I remove a Mealplan, everything gets deleted as I am expecting it. But if I want to delete a Meal, following SQL error occurs:
org.h2.jdbc.JdbcSQLIntegrityConstraintViolationException: Referentielle Integrität verletzt: "FKPIBLWWQG1HR2D5W7BGORA9XBB: PUBLIC.ESSENSPLAN_ESSEN_PRO_WOCHE FOREIGN KEY(ESSEN_PRO_WOCHE_ID) REFERENCES PUBLIC.ESSEN(ID) (1)"
Referential integrity constraint violation: "FKPIBLWWQG1HR2D5W7BGORA9XBB: PUBLIC.ESSENSPLAN_ESSEN_PRO_WOCHE FOREIGN KEY(ESSEN_PRO_WOCHE_ID) REFERENCES PUBLIC.ESSEN(ID) (1)"; SQL statement:
delete from essen where id=? [23503-200]
I am expecting that If I delete a Meal, the line in mealplan gets deleted but everything else stays the same.
Note: CasdadeType.REMOVE is not an option, because it deletes every Mealplan too, where the meal i want to remove is in it.
#Entity
public class Essen {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
}
In mealplan_meals_per_week table there is a reference of Meal in meal_per_week_id column. So where you are trying to delete Meal without cascade reference can't be resolved.
So first delete the references of Meal in mealplan_meals_per_week table and then delete Meal.
Since you are not using Entity for mealplan_meals_per_week, you can use native SQL to define query using nativeQuery.
#Query(
value = "DELETE FROM mealplan_meals_per_week m WHERE m.meal_per_week_id= ?1",
nativeQuery = true)
void deleteByMealId(Interger mealId);
Related
I am working with intelij, java, spring and hiberante to create tables in my mysql database. My code executes without a problem but for some reason hibernate creates a table I deleted. The table connected two entities with many to many relation with a composite key. One entity was deleted and so the composite key table was also deleted because it was no longer needed. I updated the other table so there is no leftover connections. I tried changing hibernates ddl-auto from update to create. It drops all and creates all with that table that doesn't exist. I also droped the whole schema in mysql workbench multiple times. I am assuming there is some leftover data somewhere in hibernate but I cannot find it especially since the same code works on another computer where it doesn't create the deleted table.
Tis is the hibernate part from my application properties:
# Hibernate properties
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
spring.jpa.properties.hibernate.globally_quoted_identifiers=true
spring.jpa.hibernate.ddl-auto=create
Below is the entity that I didn't delete that was connected to the projection_seat_list which doesn't exist anymore as well as the seat entity:
#Data
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#Entity
#Table(name = "projections")
public class Projection {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private int projectionId;
#Column(name = "date")
private String date;
#Column(name = "startTime")
private String startTime;
#ManyToOne
#JoinColumn(name = "idHall")
private Hall hall;
#ManyToOne
#JoinColumn(name = "idMovie")
private Movie movie;
#Column(name = "seatList")
#ElementCollection
private List<Integer> seatList;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "projection", cascade = CascadeType.ALL)
private List<Ticket> ticketList;
}
This is the part of the output code regarding the problem when app is executed:
Hibernate: drop table if exists `projection_seat_list`
Hibernate: drop table if exists `projections`
Hibernate: create table `projection_seat_list` (`projection_id` integer not null, `seat_list` integer) engine=MyISAM
Hibernate: create table `projections` (`id` integer not null, `date` varchar(255), `start_time` varchar(255), `id_hall` integer, `id_movie` integer, primary key (`id`)) engine=MyISAM
Hibernate: alter table `projection_seat_list` add constraint `FK8rkfyw0lua4jjaamrw3kl3llo` foreign key (`projection_id`) references `projections` (`id`)
Here is my whole code on github if you'd like to see the structure:
https://github.com/denibakulic/Java.git
It was my mistake because I had a list in my projection model and with that automatically another table is created because you can't have a list. I got confused because the name of the created table of the same of the one that I previously deleted.
i have the empty database in mysql, and two java entites. One of those have unidirectional relation. When hibernate tryes to create tables, i got the error:
Error executing DDL "alter table entry add constraint FK6ov2k83sx3crs9v3q8nvjuf1j foreign key (category_name) references category (name)" via JDBC Statement
There are my entites:
#Entity
public class Entry {
#Id
#GeneratedValue( strategy = GenerationType.IDENTITY)
private int id;
#Column
private String myfio;
private String descr;
#OneToOne(cascade = CascadeType.ALL)
private Category category;
}
And the second:
#Entity
#Table(name="category")
public class Category {
#Id
#Column
private String name;
}
How to create tables without errors?
OneToOne relationship shares the same id. So it should be the same type, but the first one is int (actually it should be Integer to allow null value for the transient (not stored) entities) and the second one is String. It seems you simply missed a line. Also, it worths to mention Vlad Mihalchea’s article https://vladmihalcea.com/the-best-way-to-map-a-onetoone-relationship-with-jpa-and-hibernate/
I have two tables that already exist inside postgres, lets call the Table A and Table B. One column of Table B has a foreign key constraint in that it has to be the primary key of Table A. Thus there is a many-to-one relationship between B and A, where multiple records in Table B correspond to one record of Table A.
The Entity for both these tables are defined as follows.
public class TableA implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "user_id")
private Long userId;
#Column(name = "name")
private String name;
#Column(name = "email")
private String email;
#Column(name = "phone_number")
private String phoneNumber;
}
TableB's entity is defined as follows:
public class Shots implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "item_id")
private Long itemId;
#Column(name = "user_id")
private Long userId;
}
Where userId is the foreign key mapping to the primary key user_id in Table A.
These constraints have already been defined in the underlying postgres database, so i didn't consider using the #ManyToOne annotation relationship (still trying to wrap my head around it).
The way i currently handle the case when a foreign key constraint violation occurs is by doing the following:
try {
tableBrepository.save(newShot);
} catch (ConstraintViolationException ex) {
logger.error("Violating foreign key constraint" + ex.getMessage());
}
My question is, is there a better way to check for this violation? Is there anything i can do to generally better structure the foreign key constraint in Spring Data JPA?
Thus there is a many-to-one relationship between B and A, where multiple records in Table B correspond to one record of Table A.
This kind of stuff in JPA entities is handled with #ManyToOne annotation. You usually do not refer to any id field directly but tell JPA what there should be. So in your class TableB (or should I call it... Shots?) should be something like:
#ManyToOne
private TableA tableA;
// and get rid of this
// #Column(name = "user_id")
// private Long userId;
And optionally - so not necessarily - you could have, in your TableA:
#OneToMany
private List<TableB> tableBsOrShouldICallYouShots;
I am not sure what is your actual problem but when setting and referring to id fields directly might cause your difficulties.
Now if you -for example- use repository to find some TableB you can then after that just do
tableB.getTableA()
And when saving you would before that do:
tableB.setTableA(somSortOftableA);
// so not tableB.setUserId(someLongIdFOrtableA);
Now the point is that there is no problem with referential integrity because you do not need to know any IDs and you cannot set any wrong ID. Unless you first need to fetch TableA by id before setting it to TableB but in that case you would still not set any IDs.
i am trying on many to many relationship, Team member can work on multiple projects and a project can have multiple team member , the table structure is as follows,
create table TBL_PROJECT_ONE(
id integer primary key generated always as identity(start with 12,increment by 3),
name varchar(50)
)
create table TBL_TEAM_MEMBER_ONE(
id integer primary key generated always as identity(start with 7,increment by 5),
name varchar(50),
salary integer
)
create table EMP_PRJ_CADRE(
MEMBER_ID integer references TBL_TEAM_MEMBER_ONE,
PRJ_ID integer references TBL_PROJECT_ONE,
CADRE varchar(10),
constraint PK_001_EMP_TEAM primary key (MEMBER_ID,PRJ_ID)
)
Here i have created a new table just to store the relationship,
Now please follow the Employee entity,
#Entity
#Table(name="TBL_TEAM_MEMBER_ONE")
public class EmployeeEntityFour implements Serializable{
public EmployeeEntityFour(){}
public EmployeeEntityFour(String empName,Integer salary){
...
..
}
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
#Column(name="ID")
private Integer empId;
#Column(name="NAME")
private String empName;
#Column(name="SALARY")
private Integer empSal;
#ElementCollection(fetch= FetchType.LAZY)
#CollectionTable(name="EMP_PRJ_CADRE")
#MapKeyJoinColumn(name="PRJ_ID")
#Column(name="CADRE")
private Map<ProjectEntityOne,String> employeeCadre;
...
..
.
}
Please follow the mapping for Project Entity,
#Entity
#Table(name="TBL_PROJECT_ONE")
public class ProjectEntityOne implements Serializable{
public ProjectEntityOne(){}
public ProjectEntityOne(String name){
this.projectName = name;
}
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
#Column(name="ID")
private Integer projectId;
#Column(name="NAME")
private String projectName;
#ElementCollection(fetch= FetchType.LAZY)
#CollectionTable(name="EMP_PRJ_CADRE")
#MapKeyJoinColumn(name="MEMBER_ID")
#Column(name="CADRE")
private Map<EmployeeEntityFour,String> employeeCadre;
....
..
.
}
In main method testing the code written is as follows,
ProjectEntityOne proj = new ProjectEntityOne("Citi Grand Central");
Map<EmployeeEntityFour,String> cadreMap = new HashMap<EmployeeEntityFour,String>();
cadreMap.put(new EmployeeEntityFour("Murlinarayan Muthu",34000), "Senior Software Engineer");
cadreMap.put(new EmployeeEntityFour("Gopalkrishna Rajnathan",64000), "Software Engineer");
cadreMap.put(new EmployeeEntityFour("Premanna Swaminathan",94000), "Project Manager");
proj.setEmployeeCadre(cadreMap);
em.persist(proj);
but i am getting an error which is
ERROR: 'PROJECTENTITYONE_ID' is not a column in table or VTI 'APP.EMP_PRJ_CADRE'.
When in both the entities i have specified #MapKeyJoinColumn than too i am getting an error as improper column for the third table.
Where i am missing
It somehow worked, i had to do some changes in the code,
first, the edited code in Entity ProjectEntityOne is as follows,
#ElementCollection(fetch= FetchType.LAZY)
#CollectionTable(name="EMP_PRJ_CADRE",joinColumns=#JoinColumn(name="PRJ_ID"))
#MapKeyJoinColumn(name="MEMBER_ID")
#Column(name="CADRE")
private Map<EmployeeEntityFour,String> employeeCadre;
What i have done here is i added #JoinedColumn in #CollectionTable,
Second change i did in Entity EmployeeEntityFour, the change is I removed Map of PorjectEntityOne from it,
in test,
i can save Project with Employee mapping but here all the employees should be already saved one.
i.e. the key of map
Map<EmployeeEntityFour,String> employeeCadre;
should be already persisted
and than we can persist project entity.
On employeeCadre in EmployeeEntityFour you need a #JoinColumn(name="MEMBER_ID") and you would also need a #JoinColumn(name="PRJ_ID") in the ProjectEntityOne employeeCadre.
But, I would not model it this way. First of all you cannot have a bi-directional ElementCollection mapping, and ElementCollection can only be owned by one side. The best solution would be to define an Cadre entity mapping to EMP_PRJ_CADRE table and have a OneToMany to it from both sides, and have it have a ManyToOne to each.
Alternatively you may use a ManyToMany with a MapKeyColumn, but I think you would be better off having an entity.
I have a problem very similar to this: How do I join tables on non-primary key columns in secondary tables?
But I'm not sure if I can apply the same solution.
I have two tables like these:
CREATE TABLE CUSTOMER
(
CUSTOMER_ID INTEGER NOT NULL,
DETAIL_ID INTEGER NOT NULL,
PRIMARY KEY( CUSTOMER_ID ),
CONSTRAINT cust_fk FOREIGN KEY( DETAIL_ID ) REFERENCES DETAILS( DETAIL_ID )
)
CREATE TABLE DETAILS
(
DETAIL_ID INTEGER NOT NULL,
OTHER INTEGER NOT NULL,
PRIMARY KEY( DETAIL_ID )
)
I'd like to map these tables to a single class called Customer, so I have:
#Entity
#Table(name = "CUSTOMERS")
#SecondaryTable(name = "DETAILS", pkJoinColumns=#PrimaryKeyJoinColumn(name="DETAIL_ID"))
public class Customer {
#Id
#GeneratedValue
#Column(name = "CUSTOMER_ID")
private Integer id;
#Column(table = "DETAILS", name = "OTHER")
private Integer notes;
// ...
}
but this works only if DETAIL_ID matches CUSTOMER_ID in the primary table.
So my question is: how can i use a foreign-key field in my primary table to join on the primary-key of the secondary table?
UPDATE
I tried to set:
#SecondaryTable(name = "DETAILS", pkJoinColumns=#PrimaryKeyJoinColumn(name="DETAIL_ID", referencedColumnName="DETAIL_ID"))
but when I run the application I get this exception:
org.hibernate.MappingException: Unable to find column with logical name: DETAIL_ID in org.hibernate.mapping.Table(CUSTOMERS) and its related supertables and secondary tables
For anyone looking for an answer to this, using #SecondaryTable is not the way to join two tables with non-primary key columns, because Hibernate will try to assosiate the two tables by their primary keys by default; you have to use #OneToMany review http://viralpatel.net/blogs/hibernate-one-to-many-annotation-tutorial/ for a solution, here's a code snippet in case that url stops working:
Customer Class:
#Entity
#Table(name="CUSTOMERS")
public class Customer {
#Id
#GeneratedValue
#Column(name="CUSTOMER_ID")
private Integer id;
#ManyToOne
#JoinColumn(name="DETAIL_ID")
private Details details;
// Getter and Setter methods...
}
Details Class:
#Entity
#Table(name="DETAILS")
public class Details {
#Id
#GeneratedValue
#Column(name="DETAIL_ID")
private int detailId;
#Column(name="OTHER")
private String other;
#OneToMany(mappedBy="details")
private Set<Customer> customers;
// Getter and Setter methods...
}
This is easily accessible through hibernate with the following code:
Session session = HibernateUtil.getSessionFactory().openSession();
Query query = session.createQuery("select id, details.other from Customer");
I hope this helps anyone out there spending hours searching for a way to achieve this like I did.
You can use the referenceColumnName attribute of the #PrimaryKeyJoinColumn annotation to define the join column to the referenced table. In fact, by combining use of name/referencedColumnName you can join on arbitrary on both sides, with the constraint that if duplicates are found your ORM provider will throw an exception.