JPA 复合键和级联
JPA Composite Keys and Cascade
我想使用 JPA CASCADE 同时保留 parent 及其 children。 parent class (Filter
) 有一个组合键 (PKFilter
)。 Aldo,children class (FilterRule
) 有它的组合键 (PKFilterRule
)。主键 class 用 @Embeddable
注释,它们被引用为 @EmbeddedId
.
PKFilter:
@Getter
@Setter
@Embeddable
@NoArgsConstructor
@AllArgsConstructor
@SuppressWarnings("JpaDataSourceORMInspection")
@EqualsAndHashCode
public class PkFilter implements Serializable {
@Column(name = "CUSTOMER_ID")
private int customerId;
@Column(name = "COMPANY_ID")
private int companyId;
@Column(name = "FILTER_ID")
private String filterId;
}
PKFilterRule:
@Getter
@Setter
@Embeddable
@NoArgsConstructor
@AllArgsConstructor
@SuppressWarnings("JpaDataSourceORMInspection")
@EqualsAndHashCode
public class PkFilterRule implements Serializable {
@Column(name = "CUSTOMER_ID")
private int customerId;
@Column(name = "COMPANY_ID")
private int companyId;
@Column(name = "FILTER_ID")
private String filterId;
@Column(name = "FILTER_RULE")
private String filterRule;
@Column(name = "FILTER_KEY")
private String filterKey;
}
过滤器
@Getter
@Setter
@Entity
@EqualsAndHashCode
@Table( name = "IOND_FILTERS")
public class Filter {
@EmbeddedId
private PkFilter pkFilter;
@Column(name = "FILTER_TARGET")
private String filterTarget;
@Column(name = "FILTER_STATUS")
private String filterStatus;
@OneToMany(mappedBy = "filter", cascade = CascadeType.ALL)
private List<FilterRule> rules;
}
过滤规则
@Getter
@Setter
@Entity
@EqualsAndHashCode
@Table( name = "IOND_FILTERS_RULES")
public class FilterRule {
@EmbeddedId
private PkFilterRule pkFilterRule;
@MapsId
@ManyToOne(cascade = CascadeType.PERSIST)
@JoinColumn(name = "CUSTOMER_ID", referencedColumnName = "CUSTOMER_ID")
@JoinColumn(name = "COMPANY_ID", referencedColumnName = "COMPANY_ID")
@JoinColumn(name = "FILTER_ID", referencedColumnName = "FILTER_ID")
private Filter filter;
}
作为测试,我们正在尝试创建一个带有 FilterItem 的过滤器,然后保留该过滤器 object:
@RunWith(SpringRunner.class)
@SpringBootTest()
@TestPropertySource(locations = {"classpath:application-test.properties"})
public class ProductsApplicationTests {
@Autowired
private FilterRepository filterRepository;
@Test
@Transactional
@Commit
public void test() {
var uuid = UUID.randomUUID().toString();
//Cria um novo Filtro
var filter = new Filter();
filter.setPkFilter(
new PkFilter(208, 210, uuid)
);
filter.setFilterTarget("ET");
filter.setFilterStatus("EN");
//Adiciona alguns itens
var filterRule = new FilterRule();
filterRule.setPkFilterRule(
new PkFilterRule(208, 210, uuid, "RULE", "KEY")
);
filterRule.setFilter(filter);
filter.setRules(Collections.singletonList(filterRule));
filterRepository.saveAndFlush(filter);
}
}
而且,作为例外,我们得到了:
Caused by: java.lang.IllegalArgumentException: Can not set int field api.products.domain.model.keys.PkFilterRule.companyId to api.products.domain.model.keys.PkFilter
at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167)
at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171)
at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:58)
at java.base/jdk.internal.reflect.UnsafeIntegerFieldAccessorImpl.getInt(UnsafeIntegerFieldAccessorImpl.java:56)
at java.base/java.lang.reflect.Field.getInt(Field.java:594)
at org.hibernate.property.access.spi.GetterFieldImpl.get(GetterFieldImpl.java:62)
... 97 more
我们缺少什么?
非常感谢!
找到解决方案:
将 PkFilterRule 更改为使用 PkFilter,如下所示:
@Getter
@Setter
@Embeddable
@NoArgsConstructor
@AllArgsConstructor
@SuppressWarnings("JpaDataSourceORMInspection")
@EqualsAndHashCode
public class PkFilterRule implements Serializable {
private PkFilter pkFilter; //<-------HERE
@Column(name = "FILTER_RULE")
private String filterRule;
@Column(name = "FILTER_KEY")
private String filterKey;
}
然后,将@MapsID 更改为如下所示:
@Getter
@Setter
@Entity
@EqualsAndHashCode
@Table(name = "IOND_FILTERS_RULES")
public class FilterRule {
@EmbeddedId
private PkFilterRule pkFilterRule;
@MapsId("pkFilter") //<------------------------------------ HERE
@ManyToOne(cascade = CascadeType.PERSIST)
@JoinColumn(name = "CUSTOMER_ID", referencedColumnName = "CUSTOMER_ID")
@JoinColumn(name = "COMPANY_ID", referencedColumnName = "COMPANY_ID")
@JoinColumn(name = "FILTER_ID", referencedColumnName = "FILTER_ID")
private Filter filter;
}
最后但同样重要的是,更改了测试:
@Test
@Transactional
@Commit
public void test() {
var uuid = UUID.randomUUID().toString();
//Cria um novo Filtro
var filter = new Filter();
filter.setPkFilter(
new PkFilter(208, 210, uuid)
);
filter.setFilterTarget("ET");
filter.setFilterStatus("EN");
//Adiciona alguns itens
var filterRule = new FilterRule();
filterRule.setPkFilterRule(
new PkFilterRule(filter.getPkFilter(), //<--------HERE
"RULE", "KEY")
);
filterRule.setFilter(filter);
filter.setRules(Collections.singletonList(filterRule));
filterRepository.saveAndFlush(filter);
}
一切都按预期进行。
谢谢!
我想使用 JPA CASCADE 同时保留 parent 及其 children。 parent class (Filter
) 有一个组合键 (PKFilter
)。 Aldo,children class (FilterRule
) 有它的组合键 (PKFilterRule
)。主键 class 用 @Embeddable
注释,它们被引用为 @EmbeddedId
.
PKFilter:
@Getter
@Setter
@Embeddable
@NoArgsConstructor
@AllArgsConstructor
@SuppressWarnings("JpaDataSourceORMInspection")
@EqualsAndHashCode
public class PkFilter implements Serializable {
@Column(name = "CUSTOMER_ID")
private int customerId;
@Column(name = "COMPANY_ID")
private int companyId;
@Column(name = "FILTER_ID")
private String filterId;
}
PKFilterRule:
@Getter
@Setter
@Embeddable
@NoArgsConstructor
@AllArgsConstructor
@SuppressWarnings("JpaDataSourceORMInspection")
@EqualsAndHashCode
public class PkFilterRule implements Serializable {
@Column(name = "CUSTOMER_ID")
private int customerId;
@Column(name = "COMPANY_ID")
private int companyId;
@Column(name = "FILTER_ID")
private String filterId;
@Column(name = "FILTER_RULE")
private String filterRule;
@Column(name = "FILTER_KEY")
private String filterKey;
}
过滤器
@Getter
@Setter
@Entity
@EqualsAndHashCode
@Table( name = "IOND_FILTERS")
public class Filter {
@EmbeddedId
private PkFilter pkFilter;
@Column(name = "FILTER_TARGET")
private String filterTarget;
@Column(name = "FILTER_STATUS")
private String filterStatus;
@OneToMany(mappedBy = "filter", cascade = CascadeType.ALL)
private List<FilterRule> rules;
}
过滤规则
@Getter
@Setter
@Entity
@EqualsAndHashCode
@Table( name = "IOND_FILTERS_RULES")
public class FilterRule {
@EmbeddedId
private PkFilterRule pkFilterRule;
@MapsId
@ManyToOne(cascade = CascadeType.PERSIST)
@JoinColumn(name = "CUSTOMER_ID", referencedColumnName = "CUSTOMER_ID")
@JoinColumn(name = "COMPANY_ID", referencedColumnName = "COMPANY_ID")
@JoinColumn(name = "FILTER_ID", referencedColumnName = "FILTER_ID")
private Filter filter;
}
作为测试,我们正在尝试创建一个带有 FilterItem 的过滤器,然后保留该过滤器 object:
@RunWith(SpringRunner.class)
@SpringBootTest()
@TestPropertySource(locations = {"classpath:application-test.properties"})
public class ProductsApplicationTests {
@Autowired
private FilterRepository filterRepository;
@Test
@Transactional
@Commit
public void test() {
var uuid = UUID.randomUUID().toString();
//Cria um novo Filtro
var filter = new Filter();
filter.setPkFilter(
new PkFilter(208, 210, uuid)
);
filter.setFilterTarget("ET");
filter.setFilterStatus("EN");
//Adiciona alguns itens
var filterRule = new FilterRule();
filterRule.setPkFilterRule(
new PkFilterRule(208, 210, uuid, "RULE", "KEY")
);
filterRule.setFilter(filter);
filter.setRules(Collections.singletonList(filterRule));
filterRepository.saveAndFlush(filter);
}
}
而且,作为例外,我们得到了:
Caused by: java.lang.IllegalArgumentException: Can not set int field api.products.domain.model.keys.PkFilterRule.companyId to api.products.domain.model.keys.PkFilter
at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167)
at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171)
at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:58)
at java.base/jdk.internal.reflect.UnsafeIntegerFieldAccessorImpl.getInt(UnsafeIntegerFieldAccessorImpl.java:56)
at java.base/java.lang.reflect.Field.getInt(Field.java:594)
at org.hibernate.property.access.spi.GetterFieldImpl.get(GetterFieldImpl.java:62)
... 97 more
我们缺少什么? 非常感谢!
找到解决方案:
将 PkFilterRule 更改为使用 PkFilter,如下所示:
@Getter
@Setter
@Embeddable
@NoArgsConstructor
@AllArgsConstructor
@SuppressWarnings("JpaDataSourceORMInspection")
@EqualsAndHashCode
public class PkFilterRule implements Serializable {
private PkFilter pkFilter; //<-------HERE
@Column(name = "FILTER_RULE")
private String filterRule;
@Column(name = "FILTER_KEY")
private String filterKey;
}
然后,将@MapsID 更改为如下所示:
@Getter
@Setter
@Entity
@EqualsAndHashCode
@Table(name = "IOND_FILTERS_RULES")
public class FilterRule {
@EmbeddedId
private PkFilterRule pkFilterRule;
@MapsId("pkFilter") //<------------------------------------ HERE
@ManyToOne(cascade = CascadeType.PERSIST)
@JoinColumn(name = "CUSTOMER_ID", referencedColumnName = "CUSTOMER_ID")
@JoinColumn(name = "COMPANY_ID", referencedColumnName = "COMPANY_ID")
@JoinColumn(name = "FILTER_ID", referencedColumnName = "FILTER_ID")
private Filter filter;
}
最后但同样重要的是,更改了测试:
@Test
@Transactional
@Commit
public void test() {
var uuid = UUID.randomUUID().toString();
//Cria um novo Filtro
var filter = new Filter();
filter.setPkFilter(
new PkFilter(208, 210, uuid)
);
filter.setFilterTarget("ET");
filter.setFilterStatus("EN");
//Adiciona alguns itens
var filterRule = new FilterRule();
filterRule.setPkFilterRule(
new PkFilterRule(filter.getPkFilter(), //<--------HERE
"RULE", "KEY")
);
filterRule.setFilter(filter);
filter.setRules(Collections.singletonList(filterRule));
filterRepository.saveAndFlush(filter);
}
一切都按预期进行。 谢谢!