Я пытаюсь установить sh связь между двумя сущностями, а именно Subscription
и Delivery
. Обе сущности должны использовать идентификатор пользователя в качестве своего первичного ключа (т. Е. Оба находятся во взаимно-однозначном отношении с User
, но Delivery
использует только идентификаторы, которые также присутствуют в Subscription
). Delivery
также использует атрибут email в качестве дополнительного ключа (вместе с идентификатором пользователя для sh составного первичного ключа). В то время как eclipselink, который я использую в качестве бэкэнда jpa для весенней загрузки, кажется, подходит для этого определения, мое приложение вылетает при включении репозитория jpa со следующим сообщением об ошибке.
Сообщение об ошибке:
Caused by: java.lang.IllegalArgumentException: Expected id attribute type [class com.tnt.entity.Subscription$DeliveryPK] on the existing id attribute [SingularAttributeImpl[EntityTypeImpl@482885994:Subscription [ javaType: class com.tnt.entity.Subscription descriptor: RelationalDescriptor(com.tnt.entity.Subscription --> [DatabaseTable(tbl_subscription)]), mappings: 6],org.eclipse.persistence.mappings.ManyToOneMapping[subscription]]] on the identifiable type [EntityTypeImpl@1615668218:Delivery [ javaType: class com.tnt.entity.Subscription$Delivery descriptor: RelationalDescriptor(com.tnt.entity.Subscription$Delivery --> [DatabaseTable(tbl_subscription_delivery)]), mappings: 2]] but found attribute type [class com.tnt.entity.Subscription].
at org.eclipse.persistence.internal.jpa.metamodel.IdentifiableTypeImpl.getId(IdentifiableTypeImpl.java:204) ~[org.eclipse.persistence.jpa-2.7.0.jar:na]
at org.springframework.data.jpa.repository.support.JpaMetamodelEntityInformation$IdMetadata.<init>(JpaMetamodelEntityInformation.java:262) ~[spring-data-jpa-2.2.3.RELEASE.jar:2.2.3.RELEASE]
at org.springframework.data.jpa.repository.support.JpaMetamodelEntityInformation.<init>(JpaMetamodelEntityInformation.java:88) ~[spring-data-jpa-2.2.3.RELEASE.jar:2.2.3.RELEASE]
at org.springframework.data.jpa.repository.support.JpaEntityInformationSupport.getEntityInformation(JpaEntityInformationSupport.java:66) ~[spring-data-jpa-2.2.3.RELEASE.jar:2.2.3.RELEASE]
at org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getEntityInformation(JpaRepositoryFactory.java:211) ~[spring-data-jpa-2.2.3.RELEASE.jar:2.2.3.RELEASE]
at org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getTargetRepository(JpaRepositoryFactory.java:161) ~[spring-data-jpa-2.2.3.RELEASE.jar:2.2.3.RELEASE]
at org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getTargetRepository(JpaRepositoryFactory.java:144) ~[spring-data-jpa-2.2.3.RELEASE.jar:2.2.3.RELEASE]
at org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getTargetRepository(JpaRepositoryFactory.java:69) ~[spring-data-jpa-2.2.3.RELEASE.jar:2.2.3.RELEASE]
at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:312) ~[spring-data-commons-2.2.3.RELEASE.jar:2.2.3.RELEASE]
at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.lambda$afterPropertiesSet$5(RepositoryFactoryBeanSupport.java:297) ~[spring-data-commons-2.2.3.RELEASE.jar:2.2.3.RELEASE]
at org.springframework.data.util.Lazy.getNullable(Lazy.java:212) ~[spring-data-commons-2.2.3.RELEASE.jar:2.2.3.RELEASE]
at org.springframework.data.util.Lazy.get(Lazy.java:94) ~[spring-data-commons-2.2.3.RELEASE.jar:2.2.3.RELEASE]
at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.afterPropertiesSet(RepositoryFactoryBeanSupport.java:300) ~[spring-data-commons-2.2.3.RELEASE.jar:2.2.3.RELEASE]
at org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean.afterPropertiesSet(JpaRepositoryFactoryBean.java:121) ~[spring-data-jpa-2.2.3.RELEASE.jar:2.2.3.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1855) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1792) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
... 88 common frames omitted
Сущности:
package com.tnt.entity;
import com.fasterxml.jackson.annotation.JsonIgnore;
import javax.persistence.*;
import java.io.Serializable;
import java.util.Objects;
@Entity
@Table(name = "tbl_subscription")
public class Subscription {
@Column(name = "user_id")
@Id
private Long id;
@Column(name = "daily_report")
@Basic
private boolean receiveDailyReport;
@Column(name = "weekly_report")
@Basic
private boolean receiveWeeklyReport;
@Column(name = "monthly_report")
@Basic
private boolean receiveMonthlyReport;
@Column(name = "multi_report")
@Basic
private boolean multiReport;
@PrimaryKeyJoinColumn(name = "user_id")
@OneToOne(optional = false)
@JsonIgnore
private User user;
public Subscription() {
}
public Subscription(User user){
this.user = user;
this.receiveDailyReport = true;
}
@Entity
@Table(name = "tbl_subscription_delivery")
@IdClass(DeliveryPK.class)
public static class Delivery {
@JoinColumn(name = "subscription_id")
@ManyToOne
@Id
private Subscription subscription;
@Column(name = "email")
@Id
private String email;
public Delivery() {
}
public Delivery(Subscription subscription, String email){
this.subscription = subscription;
this.email = email;
}
public Subscription getSubscription() {
return subscription;
}
public void setSubscription(Subscription subscription) {
this.subscription = subscription;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
// ... equals, hashCode
}
public static class DeliveryPK implements Serializable {
private Long subscription;
private String email;
public DeliveryPK() {
}
public Long getSubscription() {
return subscription;
}
public void setSubscription(Long subscription) {
this.subscription = subscription;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
// ... equals, hashCode
}
// ... getter, setter, equals, hashCode
}
Интерфейс репозитория:
interface DeliveryRepository : JpaRepository<Delivery, DeliveryPK> {
@Query("SELECT d FROM Delivery d WHERE d.subscription = :subscription AND d.email = :email")
fun findByEmail(subscription: Subscription, email: String): Optional<Delivery>
}
Кто-нибудь знает, что я делаю неправильно?
Изменить: вопрос можно было бы задать иначе - если бы я смоделировал это в SQL, это, вероятно, выглядело бы примерно так:
CREATE TABLE tbl_user (
id BIGINT NOT NULL PRIMARY KEY,
email VARCHAR(255) UNIQUE,
password VARCHAR(255),
salt VARCHAR(64)
);
CREATE TABLE tbl_subscription (
user_id BIGINT NOT NULL REFERENCES tbl_user(id),
daily_report BOOLEAN,
weekly_report BOOLEAN,
monthly_report BOOLEAN,
multi_report BOOLEAN,
PRIMARY KEY (user_id)
);
CREATE TABLE tbl_subscription_delivery (
subscription_id BIGINT NOT NULL REFERENCES tbl_subscription(user_id),
email VARCHAR(255),
PRIMARY KEY(email, subscription_id)
);
Как можно смоделировать это поведение в JPA 2.0?