I'm currently trying implement a many to many relationship in Hibernate. I followed: https://www.baeldung.com/hibernate-many-to-many however I'm getting an exception that says:
java.sql.SQLIntegrityConstraintViolationException: Cannot add or update a child row: a foreign key constraint fails (`playlist_comparer`.`playlist_tracks`, CONSTRAINT `fk_pt_track_id` FOREIGN KEY (`track_id`) REFERENCES `tracks` (`id`))
Here's the liquibase for my join table:
- createTable:
tableName: playlist_tracks
columns:
- column:
constraints:
primaryKey: true
primaryKeyName: pk_playlist_track_id
name: id
type: bigint
autoIncrement: true
- column:
name: playlist_id
type: VARCHAR(255)
constraints:
foreignKeyName: fk_pt_playlist_id
references: playlists(id)
- column:
name: track_id
type: VARCHAR(255)
constraints:
foreignKeyName: fk_pt_track_id
references: tracks(id)
and the mapping on my Hibernate objects:
Playlist.java:
#ManyToMany(cascade = {CascadeType.ALL})
#JoinTable(name = "playlist_tracks", //
joinColumns = {#JoinColumn(name = "track_id", nullable = false)}, //
inverseJoinColumns = {#JoinColumn(name = "playlist_id", nullable = false)})
private Set<Track> tracks = new HashSet<>();
Track.java:
#ManyToMany(mappedBy = "tracks")
private Set<Playlist> playlists = new HashSet<>();
I save the tracks into the DB first with no association to any playlists in one #Transactional method, leave the transactional boundary and then enter a new #Transactional method where I add the tracks to the Playlist object and then try to save that at which point I get the exception at the top.
Anyone have any ideas?
Turns out I just had the join columns the wrong way round on the join table annotation.
Related
I have an issue join fetching in case of OneToOne relation in the same class. Example follows:
class Data {
...
#Id
#Column(name = "DATA_ID")
Long id;
#Column(name = "DATA_OWNER_ID")
#ForeignKey(entityClass = Owner.class)
Long ownerId;
#Column(name = "DATA_RELATED_ID")
#ForeignKey(entityClass = Data.class)
Long relatedDataId;
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "DATA_RELATED_ID", referencedColumnName = "DATA_ID", insertable = false, updatable = false)
Data relatedData;
}
I want to select data based on some conditions, while also fetching/initialising the "relatedData", all in one JPQL query:
SELECT owner.something1, data
FROM Data data
JOIN Owner owner on data.ownerId = owner.id
JOIN FETCH data.relatedData
WHERE data.something2 = :expectedSomething2
Executing that JPQL query throws an exception:
Query: ReadObjectQuery(name="relatedData" referenceClass=Data)|Exception:
javax.persistence.PersistenceException: Exception [EclipseLink-6044] (Eclipse Persistence Services - 2.6.2.v20151217-774c696): org.eclipse.persistence.exceptions.QueryException
Exception Description: The primary key read from the row [DatabaseRecord(
DATA_X => something
DATA_Y => something2
...
)] during the execution of the query was detected to be null. Primary keys must not contain null.
Which is somewhat true, as there is no DATA_ID column listed. Changing JOIN FETCH to LEFT JOIN FETCH returns both owner.something1 and data, but the relatedData object is null (relatedDataId is not null).
I can see, that the id for relatedData is returned from DB, but eclipselink trims it in valueFromRowInternalWithJoin and trimRowForJoin methods.
The Id column name attribute value is the reason of this exception. Same issue found in eclipselink version 2.3.2 but it works fine in version 2.0.0
Try with this entry :
eclipselink.jpa.uppercase-column-names=true
OR Try with upper and lower case one by one which on will work for you.
#Id
#Column(name = "UUID") // UUID - uppercase/lowercase one by one
Long id;
I've somehow resolved this issue, but haven't had the time to correctly identify the cause. Final (working) version differences are:
I could've forgotten to add get/set for relatedData
I have specified targetEntity = Data.class in #OneToOne
Fetch is now a LEFT JOIN FETCH and appears before JOIN Owner owner
I’m looking for some help in converting the following tables into Spring Data Entities. I was somewhat able to do it but I can’t figure out enforcing the on delete and on update constraints. I have a users table that will contain info about a user. The conversations table will then have a conversation id and 2 columns to represent both id’s of the participating users. I’m writing my Solution in Kotlin, but I’m fine with advice in Java as well. Using Postgres. At the end of the day, I just want to end up with these 2 tables with the ability to change the primary key in the users table and have that carry over to the conversations table.
CREATE TABLE users (
id uuid PRIMARY KEY,
bio character varying(255),
first_name character varying(255) NOT NULL,
last_name character varying(255) NOT NULL,
password character varying(255) NOT NULL,
username character varying(255) NOT NULL UNIQUE,
zip_code character varying(255) NOT NULL
);
CREATE TABLE conversations (
convoid BIGSERIAL PRIMARY KEY,
user_id1 uuid REFERENCES users(id) on delete cascade on update cascade,
user_id2 uuid REFERENCES users(id) on delete cascade on update cascade
);
Here's what I tried:
#Data
#NoArgsConstructor
#Entity
#Table(name = "users")
data class User(
#Id //primary key
var id: UUID = UUID.randomUUID(),
#Column(nullable = false)
var firstName: String,
#Column(nullable = false)
var lastName: String,
#Column(nullable = false, unique = true)
var username: String,
#Column(nullable = false)
var password: String,
#Transient
var confirmPassword: String,
#Column(nullable = false)
var zipCode: String,
#Column(nullable=true)
var bio: String?
)
#Data
#NoArgsConstructor
#Entity
#Table(name = "conversations")
data class Conversation(
#Id //primary key
#GeneratedValue(strategy = GenerationType.IDENTITY)
val convoID: Long,
#ManyToOne(cascade = [CascadeType.ALL])
#JoinColumn(name = "user_id1")
val user1: User, //FK of user table PK
#ManyToOne(cascade = [CascadeType.ALL])
#JoinColumn(name = "user_id2")
val user2: User, //FK of user table PK
#Transient
var participants: List<WebSocketSession>
)
I'm trying to update the primary key in the users table but it isn't allowing me due to foreign key constraint. Clearly the Cascade isn't working.
In JPA relations only work in 1 way, in other to have Converation deleted when User is deleted you need to have #OneToMany relation to Converation from User. Same thing applies for update as well.
So adding property like this inside User should solve your problem:
#OneToMany(cascade = CascadeType.ALL)
val conversations: List<Conversation>
UPDATE
JPA creates separate table, it is usually solved by adding mappedBy = "mappingFieldName" to #OneToMany, but considering your case where you have 2 fields this is a bit tricky and much broader problem. You will either have to do a lot of custom querying or simply keep duplicate entries, meaning that for each new Conversation you will actually have 2 of them, so then you can say mappedBy = "user1", just remember to every time save 2 Conversations, 1 where user1 is actual user1 and another where you swap user1 and user2.
I have done a code change in a domain class(JPA). I added an ElementCollection to an entity:
#ElementCollection(targetClass = String.class)
#CollectionTable(name = "T_NETWORK_STATE", joinColumns = {#JoinColumn(name = "NETWORK_ID")})
#Column(name = "STATE")
private Set<String> states = new HashSet<>();
Now I want to write a flyway update db script for this change. I need the SQL DDL for the table T_NETWORK_STATE.
I am new to writing sql queries. any help will be appreciated!
CREATE TABLE T_NETWORK_STATE (
NETWORK_ID INT,
STATE VARCHAR(100),
UNIQUE INDEX (NETWORK_ID, STATE),
FOREIGN KEY (NETWORK_ID) REFERENCES NETWORK(NETWORK_ID)
);
I am beginner in handling JPA with maven and JBOSS, with Restful to make my application I have the following problem arose me doing DEPLOY
Caused by: javax.persistence.PersistenceException: [PersistenceUnit: com.company.test_resources_war_1.0-SNAPSHOTPU] Unable to build EntityManagerFactory
Caused by: org.hibernate.MappingException: Repeated column in mapping for entity: database.Photo column: fid_module (should be mapped with insert = \ "false \" update = \ "false \") "}}
Not that step, check all posles solutions, but did not find anything, can someone help me??
Thanks in advance
Below I show the SQL code in postgres that I have and I did the mapping.
I have three tables (activity, event and photo) where one of them (photo) refers to the other two (activity and event) but in a single column (photo.fid_module)
SQL Code (enginer database-->Postgresql):
CREATE TABLE activity (
id_activity integer not null,
name character varying(150),
description text,
CONSTRAINT id_activity_pk PRIMARY KEY (id_activity)
)
CREATE TABLE event (
id_event integer not null,
name character varying(150),
description text,
date timestamp without time zone,
CONSTRAINT id_event_pk PRIMARY KEY (id_event)
)
CREATE TABLE photo(
id_photo integer not null,
path character varying(150),
fid_module integer not null,
CONSTRAINT id_photo_pk PRIMARY KEY (id_photo),
CONSTRAINT fk_photo_activity FOREIGN KEY (fid_module)
REFERENCE activity (id_activity) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION,
CONSTRAINT fk_photo_event FOREIGN KEY (fid_module)
REFERENCE event (id_event) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
)
Now the mapping I did with the help of Netbenas and gave me the following code (I did the mapping for the three tables, but in presenting me the problem is in the class Photo.java).
#Entity
#Table(name = "photo")
#XmlRootElement
#NamedQueries({
#NamedQuery(name = "photo.findAll", query = "SELECT p FROM Photo p"),
#NamedQuery(name = "photo.findByFidPhoto", query = "SELECT p FROM Photo p WHERE p.fidphoto = :fidphoto"),
#NamedQuery(name = "photo.findByIdPhoto", query = "SELECT p FROM Photo p WHERE p.idphoto = :idphoto")})
public class Photo implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "id_photo")
private Integer idPhoto;
#Column(name = "path")
private Recurso fidPath;
#JoinColumn(name = "fid_module", referencedColumnName = "id_activity")
#ManyToOne(optional = false, fetch = FetchType.LAZY)
private SliderWebHome fidModule;
#JoinColumn(name = "fid_module", referencedColumnName = "id_event")
#ManyToOne(optional = false, fetch = FetchType.LAZY)
private Publicacion fidModule1;
public ModuloRecurso() {
}
.......
}
I am using JPA for persistence (but do mvn clean install and mvn jboss-as: deploy several pulls me hibernate dependencies) could anyone tell me what is my mistake or could solve this problem. Thank you.
You have two column mapped with the same name
#JoinColumn(name = "fid_module", referencedColumnName = "id_activity")
#JoinColumn(name = "fid_module", referencedColumnName = "id_event")
Change one of the name attribute!
Looking in your exception, you can read:
Repeated column in mapping for entity
As noted in another answer, your Java code specifies the same join-column name for two fields, which can't work.
If this Java code is generated by a netbeans mapping tool, as it seems from your note
Now the mapping I did with the help of Netbenas and gave me the following code ...
the bad Java mapping is probably caused by a bad combination of constraints in your SQL.
You have in your definition of the photo table:
CONSTRAINT fk_photo_activity FOREIGN KEY (fid_module)
REFERENCE activity (id_activity) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION,
CONSTRAINT fk_photo_event FOREIGN KEY (fid_module)
REFERENCE event (id_event) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
which attempts to make the column fid_module a foreign key referencing activity and also a foreign key referencing event, which can't work.
If you need foreign keys from photo to both of those tables, you'll need to use two different columns.
Suppose I have the following entity which models a subscriber and uses a CollectionTable to model a list of subscriptions like so:
#Entity
#Table(name = "SUBSCRIBER")
public class Subscriber {
#ElementCollection
#CollectionTable(name = "PERSON_ORG_SUBSCRIPTIONS",
joinColumns = { #JoinColumn( name = "PERSON_ID", referencedColumnName = "PERSON_ID" ),
#JoinColumn( name = "ORG_ID", referencedColumnName = "ORG_ID" ) } )
#Column(name = "SUBSCRIPTION_NAME")
protected Set<String> _subscriptionNames;
}
So this creates a table with columns for PERSON_ID, ORG_ID and SUBSCRIPTION_NAME.
I'm trying to create a database index on the SUBSCRIPTION_NAME column. But if I put the following annotation on _subscriptionNames:
#org.hibernate.annotations.Index( name="subscription_idx", columnNames={"SUBSCRIPTION_NAMES"} )
I get an exception:
org.hibernate.MappingException: Unable to find logical column name from physical name null in table SUBSCRIBER
I also tried using the org.hibernate.annotations.Table annotation on the Subscriber entity, but there does not seem to be a way to have it reference the PERSON_ORG_SUBSCRIPTIONS table.
I'm using Hibernate 3.5.3 and PostgreSQL 9.0.
Is the column with name "SUBSCRIPTION_NAME" present in the table SUBSCRIBER?
Are you planning to create index on table from the code? You should propably use hibernate.hbm2ddl.auto=create