Reputation: 5489
i created an entity with a composite id that looks like this:
@Entity
@IdClass(CompId.class)
public class CompEntity {
@Id
@ManyToOne(optional = false)
private AccountEntity account;
@Id
@ManyToOne(optional = false)
private ProductEntity product;
...
}
With the CompId looks like this:
public class CompId implements Serializable {
private Long account;
private Long product;
}
Both account and product use simple Long ids that are auto-generated.
In Unit tests, everything works. In a runing server when i try to save a new CompEntity, i get the following error:
org.springframework.dao.InvalidDataAccessApiUsageException: Can not set java.lang.Long field CompId.product to ProductEntity_$$_jvstd2f_36; nested exception is java.lang.IllegalArgumentException: Can not set java.lang.Long field CompId.product to ProductEntity_$$_jvstd2f_36
As as far as i understand jpa and online examples, this should work, so i have no idea what is going wrong.
I'm thankful for any advice.
EDIT1:
Here are the ProductEntity and AccountEntity
@Entity
public class AccountEntity implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
...
}
@Entity
public class ProductEntity implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
...
}
EDIT 2:
And the repository for CompEntity
public interface CompRepository extends JpaRepository<CompEntity, CompId> {
...
}
Upvotes: 2
Views: 2730
Reputation: 1577
The @IdClass is used to create a composite key in hibernate entities.
If the parent class has a single key then use the Single Key's datatype in the @IdClass of the child.
Example:
//Parent
@Entity
@Table(name = "GROUP")
public class Group implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "GROUP_ID")
private Long groupId;
...
}
//Child
@Entity
@Table(name = "RECORD")
@IdClass(RecordId.class)
public class Record implements Serializable {
@Id
@Column(name = "FIELD_ID")
private Long fieldId;
@Id
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="GROUP_ID") //Join Column is just for naming purposes
private Group group;
...
}
//Composite Id for Record
public class RecordId implements Serializable {
private Long fieldId;
//Use the @Id datatype from Group
private Long group;
//Getters, Setters, and Constructor omitted for space
}
If the parent class has a composite Id class then use the composite Id class as the datatype in the @IdClass of the child.
Example:
//Parent
@Entity
@Table(name = "GROUP")
@IdClass(GroupId.class)
public class Group implements Serializable {
@Id
@Column(name = "GROUP_ID")
private Long groupId;
@Id
@Column(name = "GROUP_NAME")
private String groupName
...
}
//Composite Id for Group
public class GroupId implements Serializable {
private Long groupId;
//Use the @Id datatype from Group
private String groupName;
//Getters, Setters, and Constructor omitted for space
}
//Child
@Entity
@Table(name = "RECORD")
@IdClass(RecordId.class)
public class Record implements Serializable {
@Id
@Column(name = "FIELD_ID")
private Long fieldId;
/*
* JoinColumns is just used for naming columns:
* -(name) indicates the column to create in this table Record
* -(referencedColumnName) indicates the corresponding column in the parent Group
*/
@Id
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumns({
@JoinColumn(name="GROUP_ID", referencedColumnName="GROUP_ID"),
@JoinColumn(name="GROUP_NAME", referencedColumnName="GROUP_NAME")
})
private Group group;
...
}
//Composite Id for Record
public class RecordId implements Serializable {
private Long fieldId;
//Use the @IdClass for the datatype because the parent has a composite key.
private GroupId group;
//Getters, Setters, and Constructor omitted for space
}
I put the bounty, and discovered I wasn't using the correct datatype in the child's @IdClass for the parent. I'm putting the rules for @IdClass creation in this answer to hopefully help others.
P.S.
The wrong @IdClass I originally created, and was the cause of my headache the other day.
//Composite Id for Record
public class RecordId implements Serializable {
private Long fieldId;
/*
* WRONG WAY
*
* The cause of my error was due to the wrong dataype being used in this child
@IdClass.
*/
private Group group;
//Getters, Setters, and Constructor omitted for space
}
Upvotes: 1
Reputation: 318
You need to have @JoinColumn on your relationships to specify which column to refer in that entity.
@Entity
@IdClass(CompId.class)
public class CompEntity {
@Id
@ManyToOne(optional = false)
@JoinColumn(name = "account_id")
private AccountEntity account;
@Id
@ManyToOne(optional = false)
@JoinColumn(name = "product_id")
private ProductEntity product;
}
Upvotes: 0