@Id 字段上的继承和@AttributeOverride
Inheritance and @AttributeOverride on @Id field
我有一个实体需要手动设置 ID (PK)。
我有一些 Abstract @MappedSuperclass 用于审计和 PK,我仍然想使用它。所以我的想法是覆盖 id 列以摆脱 @GeneratedValue(strategy = GenerationType.AUTO.
所以我有这样的东西:
@Entity
@Table(name = Constants.MERCHANT_PREFIX + "MERCHANT")
@Cacheable(false)
public class Merchant extends AbstractAuditable<String, Long> {
@AttributeOverride(name = "id", column = @Column(name="ID"))
private Long id;
@Override
public Long getId() {
return id;
}
@Override
public void setId(Long id) {
this.id = id;
}
}
@MappedSuperclass
@EntityListeners(value = { AuditingEntityListener.class })
public abstract class AbstractAuditable<U, PK extends Serializable> extends AbstractPersistable<PK> {
...
}
@MappedSuperclass
public abstract class AbstractPersistable<PK extends Serializable> implements Persistable<PK> {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "ID")
private PK id;
public PK getId() {
return id;
}
protected void setId(final PK id) {
this.id = id;
}
}
它工作正常(服务器已启动并大摇大摆)
但是我的集成测试失败了,下面有这个错误。
你知道为什么吗?我想也许我不应该以这种方式使用@AttributeOverride ...我想找到一种与我的商家class一起工作的方法仍然扩展我的抽象classes(审计和PK)
org.springframework.dao.InvalidDataAccessResourceUsageException:
could not prepare statement;
SQL [insert into MER_MERCHANT (ID, CREATED_BY, CREATED_DATE, LAST_MODIFIED_BY, LAST_MODIFIED_DATE, ALLOW_ACCESS, id)
values (default, ?, ?, ?, ?, ?, ?)];
nested exception is org.hibernate.exception.SQLGrammarException:
could not prepare statement
单元测试:
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(classes = {ApplicationTest.class})
@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
TransactionalTestExecutionListener.class,
DbUnitTestExecutionListener.class })
@DatabaseSetup(value = "classpath:merchantData.xml")
@DatabaseTearDown(value="classpath:merchantData.xml", type = DatabaseOperation.DELETE_ALL)
public class RestMerchantControllerTest extends AbstractControllerTest {
@Test
public void testCreateMerchant() throws Exception {
final Long merchantId = 2L;
final Boolean allowAccess = true;
MerchantCreateVO merchantCreateVO = StubVOBuilder.buildMerchantCreateVO(allowAccess);
String requestBody = JsonUtils.jsonFormat(merchantCreateVO);
mvc.perform(post("/merchants/" + merchantId).contentType(MediaType.APPLICATION_JSON).content(requestBody)).andExpect(status().isOk());
}
}
还有ApplicationTest:(ApplicationTest很像我们用来设置JPA的Application)
@Configuration
@ComponentScan(value = "uk.co.xxx.yyy", excludeFilters = @ComponentScan.Filter(value=Configuration.class, type = FilterType.ANNOTATION ))
@EnableWebMvc
@EnableTransactionManagement
@PropertySources({@PropertySource("classpath:hibernate.properties"), @PropertySource("classpath:junit-persistence.properties"), @PropertySource("classpath:application-test.properties")})
@EnableJpaRepositories(basePackages = "uk.co.xxx.yyy.merchant.data.repository")
@EnableJpaAuditing(auditorAwareRef = "springSecurityAuditorAware")
public class ApplicationTest {
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(){
...
}
@Bean
public JpaTransactionManager transactionManager() {
...
}
}
通过服务器,我得到了这个插件:
insert
into
MER_MERCHANT
(CREATED_BY, CREATED_DATE, LAST_MODIFIED_BY, LAST_MODIFIED_DATE, ALLOW_ACCESS, id)
values
(?, ?, ?, ?, ?, ?)
并进行集成测试:
insert
into
MER_MERCHANT
(ID, CREATED_BY, CREATED_DATE, LAST_MODIFIED_BY, LAST_MODIFIED_DATE, ALLOW_ACCESS, id)
values
(default, ?, ?, ?, ?, ?, ?)
So my idea was to override the id column to get rid off the
@GeneratedValue(strategy = GenerationType.AUTO.
@AttributeOverride 批注用于向 JPA 发出信号,表明您希望更改属性名称到列名称的默认映射。如果您正在开发与旧系统互操作的 JPA 应用程序,而旧系统的字段或列的名称与您的名称不同,则需要这样做。
根据 JavaDoc,@AttributeOverride 是...
用于覆盖 Basic(显式或默认)属性 或字段或 Id 属性 或字段的映射。
可应用于扩展映射超的实体class或嵌入字段或属性以覆盖映射超定义的基本映射或id映射class or embeddable class(或者其属性之一的可嵌入class)。
不幸的是,此注释仅对 属性 或可通过 @Column API 引用的字段映射有效...并且 @Column 注释基本上只允许您更改映射的字段名称。您不能使用 @AttributeOverride 更改字段类型或任何其他映射。因此,@GeneratedValue 映射将继续被 @MappedSuperclass.
的所有子class继承。
我有一个实体需要手动设置 ID (PK)。 我有一些 Abstract @MappedSuperclass 用于审计和 PK,我仍然想使用它。所以我的想法是覆盖 id 列以摆脱 @GeneratedValue(strategy = GenerationType.AUTO.
所以我有这样的东西:
@Entity
@Table(name = Constants.MERCHANT_PREFIX + "MERCHANT")
@Cacheable(false)
public class Merchant extends AbstractAuditable<String, Long> {
@AttributeOverride(name = "id", column = @Column(name="ID"))
private Long id;
@Override
public Long getId() {
return id;
}
@Override
public void setId(Long id) {
this.id = id;
}
}
@MappedSuperclass
@EntityListeners(value = { AuditingEntityListener.class })
public abstract class AbstractAuditable<U, PK extends Serializable> extends AbstractPersistable<PK> {
...
}
@MappedSuperclass
public abstract class AbstractPersistable<PK extends Serializable> implements Persistable<PK> {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "ID")
private PK id;
public PK getId() {
return id;
}
protected void setId(final PK id) {
this.id = id;
}
}
它工作正常(服务器已启动并大摇大摆)
但是我的集成测试失败了,下面有这个错误。 你知道为什么吗?我想也许我不应该以这种方式使用@AttributeOverride ...我想找到一种与我的商家class一起工作的方法仍然扩展我的抽象classes(审计和PK)
org.springframework.dao.InvalidDataAccessResourceUsageException:
could not prepare statement;
SQL [insert into MER_MERCHANT (ID, CREATED_BY, CREATED_DATE, LAST_MODIFIED_BY, LAST_MODIFIED_DATE, ALLOW_ACCESS, id)
values (default, ?, ?, ?, ?, ?, ?)];
nested exception is org.hibernate.exception.SQLGrammarException:
could not prepare statement
单元测试:
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(classes = {ApplicationTest.class})
@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
TransactionalTestExecutionListener.class,
DbUnitTestExecutionListener.class })
@DatabaseSetup(value = "classpath:merchantData.xml")
@DatabaseTearDown(value="classpath:merchantData.xml", type = DatabaseOperation.DELETE_ALL)
public class RestMerchantControllerTest extends AbstractControllerTest {
@Test
public void testCreateMerchant() throws Exception {
final Long merchantId = 2L;
final Boolean allowAccess = true;
MerchantCreateVO merchantCreateVO = StubVOBuilder.buildMerchantCreateVO(allowAccess);
String requestBody = JsonUtils.jsonFormat(merchantCreateVO);
mvc.perform(post("/merchants/" + merchantId).contentType(MediaType.APPLICATION_JSON).content(requestBody)).andExpect(status().isOk());
}
}
还有ApplicationTest:(ApplicationTest很像我们用来设置JPA的Application)
@Configuration
@ComponentScan(value = "uk.co.xxx.yyy", excludeFilters = @ComponentScan.Filter(value=Configuration.class, type = FilterType.ANNOTATION ))
@EnableWebMvc
@EnableTransactionManagement
@PropertySources({@PropertySource("classpath:hibernate.properties"), @PropertySource("classpath:junit-persistence.properties"), @PropertySource("classpath:application-test.properties")})
@EnableJpaRepositories(basePackages = "uk.co.xxx.yyy.merchant.data.repository")
@EnableJpaAuditing(auditorAwareRef = "springSecurityAuditorAware")
public class ApplicationTest {
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(){
...
}
@Bean
public JpaTransactionManager transactionManager() {
...
}
}
通过服务器,我得到了这个插件:
insert
into
MER_MERCHANT
(CREATED_BY, CREATED_DATE, LAST_MODIFIED_BY, LAST_MODIFIED_DATE, ALLOW_ACCESS, id)
values
(?, ?, ?, ?, ?, ?)
并进行集成测试:
insert
into
MER_MERCHANT
(ID, CREATED_BY, CREATED_DATE, LAST_MODIFIED_BY, LAST_MODIFIED_DATE, ALLOW_ACCESS, id)
values
(default, ?, ?, ?, ?, ?, ?)
So my idea was to override the id column to get rid off the @GeneratedValue(strategy = GenerationType.AUTO.
@AttributeOverride 批注用于向 JPA 发出信号,表明您希望更改属性名称到列名称的默认映射。如果您正在开发与旧系统互操作的 JPA 应用程序,而旧系统的字段或列的名称与您的名称不同,则需要这样做。
根据 JavaDoc,@AttributeOverride 是...
用于覆盖 Basic(显式或默认)属性 或字段或 Id 属性 或字段的映射。
可应用于扩展映射超的实体class或嵌入字段或属性以覆盖映射超定义的基本映射或id映射class or embeddable class(或者其属性之一的可嵌入class)。
不幸的是,此注释仅对 属性 或可通过 @Column API 引用的字段映射有效...并且 @Column 注释基本上只允许您更改映射的字段名称。您不能使用 @AttributeOverride 更改字段类型或任何其他映射。因此,@GeneratedValue 映射将继续被 @MappedSuperclass.
的所有子class继承。