I have a relation between Accommodation and Booking classes, and also I set a foreign key in booking table.
ALTER TABLE `project`.`booking`
ADD INDEX `fk_accId_fk_idx` (`accommodation` ASC);
ALTER TABLE `project`.`booking`
ADD CONSTRAINT `fk_accId_fk`
FOREIGN KEY (`accommodation`)
REFERENCES `project`.`accommodation` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION;
Accommodation class:
#Entity
....
public class Accommodation implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", unique = true, nullable = false)
private BigInteger id;
#OneToMany(mappedBy = "accommodation", fetch = FetchType.EAGER, cascade = CascadeType.REMOVE)
#JsonManagedReference
private List < Booking > bookings;
......getters setters
}
Booking class:
#Entity
public class Booking implements Serializable {
......
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "bookings", nullable = true)
#JsonBackReference
private Accommodation accommodation;
....getters setters
}
When I execute a query for listing accommodations, I get unknown column in field list error.
javax.persistence.PersistenceException: org.hibernate.exception.SQLGrammarException: could not extract ResultSet] with root cause
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'bookings7_.bookings' in 'field list'
Even I set the relation and define the foreign key in table, what is the reason that I get this error?
Try to define your join-table mapping manually in JPA. Drop your schema and let JPA create your tables:
Accommodation class
#OneToMany(mappedBy = "accommodation", fetch = FetchType.EAGER, cascade = CascadeType.REMOVE)
#JsonManagedReference
private List < Booking > bookings;
Booking class
#ManyToOne(fetch = FetchType.EAGER)
#JoinTable(name = "accommodation_booking_join_table",
joinColumns = {#JoinColumn(name="booking_id")},
inverseJoinColumns = #JoinColumn(name = "accommodation_id"))
#JsonBackReference
private Accommodation accommodation;
Try changing your column names to lower case in your db and entity class.
I had a situation like that, and I solved it by changing the field's position on the query. Looks like it's a MySQL bug, like (or the same as) the one mentioned on this post:
https://bugs.mysql.com/bug.php?id=1689
The description of this MySQL bug mentioned a similar workaround solution: "I found that by swapping that field's position in the table with another field that it worked OK."
Related
I have 2 entities, Event and Tag, in a many-to-many relationship. Tags should have unique names, so I placed a constraint on it.
It works like expected for unique tag names, I save a batch of new events and entries are automatically inserted in the tag and join tables.
But the moment I try to save an event that has a tag with a duplicate name, an error is thrown due to it violating the constraint.
Is there a way around this that does not involve having to check and insert all the events/tags manually?
Code below:
Event entity:
#Entity
#Table(name = "event")
class Event {
#Id long id;
#ManyToMany(cascade = { CascadeType.ALL })
#JoinTable(name = "event_tag",
joinColumns = #JoinColumn(name = "event_id"),
inverseJoinColumns = #JoinColumn(name = "tag_id"))
private Set<Tag> tags;
// other properties
}
Tag entity:
#Entity
#Table(name = "tag", uniqueConstraints = #UniqueConstraint(columnNames = "name"))
public class Tag {
#Id long id;
#Column(name = "name", unique = true)
private String name;
#ManyToMany(mappedBy = "tags", cascade = { CascadeType.ALL })
private Set<Event> events;
}
I'm using JpaRepository's method saveAll to persist the events. It throws:
java.sql.SQLException: Duplicate entry 'xxxxx' for key 'uq_tag_name'
at org.mariadb.jdbc.internal.protocol.AbstractQueryProtocol.readErrorPacket(AbstractQueryProtocol.java:1694) ~[mariadb-java-client-2.7.3.jar:na]
I have seen a few similar questions but have yet to find a working answer for this.
it happen because of { CascadeType.ALL }
when you set CascadeType.ALL hibernate changes the Tag table and if it need,insert data for Tag.you should remove CascadeType.ALL and if you get (cannot insert transient object) should use flush for handlinf that
I have a problem with deleting entity from database. Whatever I do anyway it doesn't delete.
Driver class
#Entity
#Table(name = "drivers")
public class Driver {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToMany(mappedBy = "driver", fetch = FetchType.EAGER)
#JsonSerialize(using = RatingsSerializer.class)
private List<Rating> ratings;
// other fields. Getters and Setters...
}
Rating class
#Entity
#Table(name = "ratings")
#JsonDeserialize(using = RatingDeserializer.class)
public class Rating {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne
#JoinColumn(name = "driver_id")
private Driver driver;
#ManyToOne
#JoinColumn(name = "client_id")
private Client client;
private int mark;
private Date createdAt;
//Getters and Setters ...
}
First one what I do is annotate ratings with #OneToMany(mappedBy = "driver", fetch = FetchType.EAGER, orphanRemoval = true, cascade = CascadeType.REMOVE) and when call driverRepository.delete(driver) it throws:
org.postgresql.util.PSQLException: ERROR: update or delete on table "drivers" violates foreign key constraint "fk3raf3d9ucm571r485t8e7ew83" on table "ratings"
Ok, choose another way. Try to delete each rating object using ratingRepository, but never happens, it just iterate thorough each rating item and throw again error
org.postgresql.util.PSQLException
Next step was to set for each rating item Client and Driver to null. Now driver entity is deleted from database but rating entity remain in database.
What happens?
Spring Data JPA version: 1.5.7
It looks that your Foreign Key error is related to Client table which is linked according to your code line:
#ManyToOne
#JoinColumn(name = "client_id")
private Client client;
So, if you add cascade = CascadeType.REMOVE within the annotation, it may works. But, that' up to you if you want to delete everything on cascade including Client row. If not, then update that column value first to null.
I am working with one-to-many relation using hibernate.
profesor.java
#Entity
public class Profesor {
#Id
#GeneratedValue(strategy = GenerationType.TABLE)
private Long id;
#ManyToMany(mappedBy = "profesors", fetch = FetchType.EAGER, cascade = { CascadeType.MERGE, CascadeType.PERSIST })
private List<Classes> classes;
#OneToMany(mappedBy="profesor", fetch = FetchType.EAGER, cascade = { CascadeType.MERGE, CascadeType.PERSIST })
#Fetch(value = FetchMode.SUBSELECT)
private List<Post> post;
}
My professor table is already in relation with classes table as many-to-many. Now I am trying to connect it with post table as one-to-many.
My post model looks like this:
post.java
#Entity
public class Post {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id", unique = true, nullable = false)
private long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn (name="profesor_id",referencedColumnName="id",nullable=false,unique=true)
private Profesor profesor;
}
Here is how my table post looks in database.
I am getting following error:
Cannot add or update a child row: a foreign key constraint fails (`database`.`#sql-45e3_695`, CONSTRAINT `FKfkqyncksuk5vuw09wam4sryyd` FOREIGN KEY (`profesor_id`) REFERENCES `profesor` (`id`))
What am I doing wrong?
SOLUTION:
First I created post table without profesor_id. I added profesor_id when I started to create relationship between tables and then profesor_id was set to null. When I cleared my table I could run my application normally.
its clear you are violating some constraint, i would say you are trying to remove a proffesor which is already linked to post, try to remove nullable = false
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn (name="profesor_id",referencedColumnName="id",unique=true)
private Profesor profesor;
I have a many-to-many relationship with three tables and entities adn the join table contains additional column. On both sides of the relationship I have set cascadeType.All
When I add new objects to owner side the merge method works fine but when I remove a child object from the owner and merge it, the corresponding rows in the join table will not be removed and I will have duplicate rows in there.
owner entity
#OneToMany(cascade=CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "definitionType")
private List<DefinitionProperty> definitionProperties = new ArrayList<DefinitionProperty>();
#OneToMany(cascade=CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "property")
private List<DefinitionProperty> definitionProperties= new ArrayList<DefinitionProperty>();
mapping entity
#Id
#JoinColumn(name = "dtid", referencedColumnName = "id")
#ManyToOne(optional = false)
private DefinitionType definitionType;
#Id
#JoinColumn(name = "prid", referencedColumnName = "id")
#ManyToOne(optional = false)
private Property property;
I am not calling remove method of my entity manager at all and I am expecting the cascading to remove the unwanted rows automatically. Is that possible? what should I do to in order to remove those rows?
I can add my code here if it help
It just needed orphanRemoval=true on the owner side.
i would like to create an application in this context : Zk 6, Spring v3.1.1, JPA 2.0, Hibernate 4.1.4, all with annotations but i have some pb with JPA concept.
Here are a type of case study :
3 tables, all linked via a join table ; we are dealing with cardinality 0, n.
So we have T_E_USER, T_E_TYPE and T_E_AIR.
Each table has a numeric ID, and a simple VARCHAR field.
A join table is created with T_J_USR_TPE_AIR with the 3 ID referenced by foreign keys forming a composed primary key.
I'm using Hibernate Tools for generate my entities (version JPA).
And that's where the problems start ....
I have, in each entity class, an attribute of type set with annotation # OneToMany.
I have a class representing the join that has an id attribute of complex type (another class) with an annotation EmbeddedId for a composite key.
And attributes representing the three entities with annotations # ManyToOne.
Here are my questions, because that's where I'm confused:
which should i set into the "mappedBy" attribute in the annotation # OneToMany of my entities?
Am I forced to do a class entity representing the join?
How does the CASCADE? Is it possible to use it in this context to enrich the join table "automatically"? Or should I manually instantiate the class representative of the join in order to persist the information myself?
A big thank you in advance for any kind soul who could give me a helping hand.
Thank you for your answers but one said "yes" when the other says "no" lol
Here's what I did during the day but I have not yet been tested.
In each entity table, i added a #OneToMany relation with mappedBy setted to the attribute defined in "join" entity :
#OneToMany(fetch = FetchType.LAZY,
mappedBy = "aircraft",
cascade = { CascadeType.REMOVE })
private Set<UserConfig> userConfigs = new HashSet<UserConfig>(0);
...
#OneToMany(fetch = FetchType.LAZY,
mappedBy = "userAccount",
cascade = { CascadeType.REMOVE })
private Set<UserConfig> userConfigs = new HashSet<UserConfig>(0);
...
#OneToMany(fetch = FetchType.LAZY,
mappedBy = "referenceType",
cascade = { CascadeType.REMOVE })
private Set<UserConfig> userConfigs = new HashSet<UserConfig>(0);
And i created a new Entity for the join table.
#Entity
#Table(name = "T_J_USR_RFT_AIR_URA")
public class UserConfig implements java.io.Serializable {
#EmbeddedId
#AttributeOverrides({
#AttributeOverride(name = "airId",
column = #Column(name = "URA_AIR_ID", nullable = false)),
#AttributeOverride(name = "usrId",
column = #Column(name = "URA_USR_ID", nullable = false)),
#AttributeOverride(name = "rftId",
column = #Column(name = "URA_RFT_ID", nullable = false))
})
private UserConfigId id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "URA_RFT_ID", nullable = false, insertable = false, updatable = false)
private ReferenceType referenceType;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "URA_USR_ID", nullable = false, insertable = false, updatable = false)
private UserAccount userAccount;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "URA_AIR_ID", nullable = false, insertable = false, updatable = false)
private Aircraft aircraft;
...
getter & setter
}
Where UserConfigId is :
#Embeddable
public class UserConfigId implements java.io.Serializable {
#Column(name = "URA_AIR_ID", nullable = false)
private Integer airId;
#Column(name = "URA_USR_ID", nullable = false)
private Integer usrId;
#Column(name = "URA_RFT_ID", nullable = false)
private Integer rftId;
...
getter & setter
}
What do you think about this practice ?
I just used "cascade" if an object of the join table is deleted in order to delete all element associated in the join.
Is it all right ?
Anyway thank you Tom, i will analyzed your link.
Thank you JMelnyk too.
You are welcome if you want to demonstrate what are the best practices for this case.
Three-way joins are tricky. I think what you've done, using an entity for the join table, is probably the right thing to do. To answer your questions:
Your #OneToMany attributes refer to the entity mapping the join table; they should be mappedBy the appropriate #ManyToOne attribute in that entity.
Yes, unfortunately, an entity for the join table is the best way to do this.
Cascades can be used to automatically add objects to the database, but not to create objects. You will need to create instances of the join entity in code.
which should i set into the "mappedBy" attribute in the annotation #
OneToMany of my entities?
mappedBy attribute represents a property name you are joining on. Read more...
e.g. AnyEntity holds List<Employee> which is joined on (mappedBy) department property in Employee entity, and that department property holds the association.
Am I forced to do a class entity representing the join?
No, you do not provide an entity class for join tables.
How does the CASCADE? Is it possible to use it in this context to
enrich the join table "automatically"? Or should I manually
instantiate the class representative of the join in order to persist
the information myself?
Yes it is possible to enrich associations of the entity and itself by marking associations with desired cascade type.
e.g. We have a Department which holds List<Employee> and I put CascadeType.PERSIST on employees. Now we populate department objects with its properties and employees. When we are finished, we persist only the department, and it will cascade operation to employees.