英文:
Spring Boot - Have hierarchical classes for entities, parent contains the ID
问题
我正在为现有的SQL数据库创建一个API。我的类系统工作方式如下:
@Data
@NoArgsConstructor
public class ParentStat {
@Id
@Column(name = "uuid", unique = true, nullable = false)
private String UUID;
// 更多字段
}
@Entity
@Data
@Table(name = "some_data")
public class ChildStat extends ParentStat {
// 字段
}
使子状态不扩展游戏状态并仅包含其方法是可行的,但扩展该类会导致代码无法编译(IDE还建议ChildStat应该有一个Id)。
我尝试将ParentStat设置为抽象,但没有成功。对于如何解决此问题有什么想法?
编辑:我将导入更改为javax.persistence现在出现以下错误:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'gameStatController': Unsatisfied dependency expressed through field 'sqlService': Error creating bean with name 'SQLService': Unsatisfied dependency expressed through field 'sqlRepository': Error creating bean with name 'SQLRepository' defined in org.randomcraft.PlayerDataAPI.repositories.SQLRepository defined in @EnableJpaRepositories declared on PlayerDataApiApplication: Not a managed type: class org.randomcraft.PlayerDataAPI.classes.instances.DRStat
英文:
I'm creating an API for an existing SQL database. My class system works the following way:
@Data
@NoArgsConstructor
public class ParentStat {
@Id
@Column(name = "uuid", unique = true, nullable = false)
private String UUID;
// More fields
}
@Entity
@Data
@Table(name = "some_data")
public class ChildStat extends ParentStat {
// Fields
}
Having the child stat not extend game stat and just contain it's methods works, but extending the class makes the code not compile (IDE also suggests ChildStat should have an Id).
I tried making the ParentStat abstract and it did not work. Any ideas on what could fix the issue?
EDIT: I changed the imports to javax.persistence and now the following error appears:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'gameStatController': Unsatisfied dependency expressed through field 'sqlService': Error creating bean with name 'SQLService': Unsatisfied dependency expressed through field 'sqlRepository': Error creating bean with name 'SQLRepository' defined in org.randomcraft.PlayerDataAPI.repositories.SQLRepository defined in @EnableJpaRepositories declared on PlayerDataApiApplication: Not a managed type: class org.randomcraft.PlayerDataAPI.classes.instances.DRStat
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.resolveFieldValue(AutowiredAnnotationBeanPostProcessor.java:712) ~[spring-beans-6.0.6.jar:6.0.6]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:692) ~[spring-beans-6.0.6.jar:6.0.6]
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:133) ~[spring-beans-6.0.6.jar:6.0.6]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:481) ~[spring-beans-6.0.6.jar:6.0.6]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1408) ~[spring-beans-6.0.6.jar:6.0.6]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:598) ~[spring-beans-6.0.6.jar:6.0.6]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:521) ~[spring-beans-6.0.6.jar:6.0.6]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326) ~[spring-beans-6.0.6.jar:6.0.6]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-6.0.6.jar:6.0.6]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324) ~[spring-beans-6.0.6.jar:6.0.6]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[spring-beans-6.0.6.jar:6.0.6]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:961) ~[spring-beans-6.0.6.jar:6.0.6]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:917) ~[spring-context-6.0.6.jar:6.0.6]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:584) ~[spring-context-6.0.6.jar:6.0.6]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) ~[spring-boot-3.0.4.jar:3.0.4]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:732) ~[spring-boot-3.0.4.jar:3.0.4]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:434) ~[spring-boot-3.0.4.jar:3.0.4]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:310) ~[spring-boot-3.0.4.jar:3.0.4]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1304) ~[spring-boot-3.0.4.jar:3.0.4]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1293) ~[spring-boot-3.0.4.jar:3.0.4]
at org.randomcraft.PlayerDataAPI.PlayerDataApiApplication.main(PlayerDataApiApplication.java:12) ~[classes/:na]
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'SQLService': Unsatisfied dependency expressed through field 'sqlRepository': Error creating bean with name 'SQLRepository' defined in org.randomcraft.PlayerDataAPI.repositories.SQLRepository defined in @EnableJpaRepositories declared on PlayerDataApiApplication: Not a managed type: class org.randomcraft.PlayerDataAPI.classes.instances.DRStat
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.resolveFieldValue(AutowiredAnnotationBeanPostProcessor.java:712) ~[spring-beans-6.0.6.jar:6.0.6]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:692) ~[spring-beans-6.0.6.jar:6.0.6]
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:133) ~[spring-beans-6.0.6.jar:6.0.6]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:481) ~[spring-beans-6.0.6.jar:6.0.6]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1408) ~[spring-beans-6.0.6.jar:6.0.6]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:598) ~[spring-beans-6.0.6.jar:6.0.6]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:521) ~[spring-beans-6.0.6.jar:6.0.6]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326) ~[spring-beans-6.0.6.jar:6.0.6]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-6.0.6.jar:6.0.6]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324) ~[spring-beans-6.0.6.jar:6.0.6]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[spring-beans-6.0.6.jar:6.0.6]
at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) ~[spring-beans-6.0.6.jar:6.0.6]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1405) ~[spring-beans-6.0.6.jar:6.0.6]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1325) ~[spring-beans-6.0.6.jar:6.0.6]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.resolveFieldValue(AutowiredAnnotationBeanPostProcessor.java:709) ~[spring-beans-6.0.6.jar:6.0.6]
... 20 common frames omitted
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'SQLRepository' defined in org.randomcraft.PlayerDataAPI.repositories.SQLRepository defined in @EnableJpaRepositories declared on PlayerDataApiApplication: Not a managed type: class org.randomcraft.PlayerDataAPI.classes.instances.DRStat
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1762) ~[spring-beans-6.0.6.jar:6.0.6]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:599) ~[spring-beans-6.0.6.jar:6.0.6]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:521) ~[spring-beans-6.0.6.jar:6.0.6]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326) ~[spring-beans-6.0.6.jar:6.0.6]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-6.0.6.jar:6.0.6]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324) ~[spring-beans-6.0.6.jar:6.0.6]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[spring-beans-6.0.6.jar:6.0.6]
at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) ~[spring-beans-6.0.6.jar:6.0.6]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1405) ~[spring-beans-6.0.6.jar:6.0.6]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1325) ~[spring-beans-6.0.6.jar:6.0.6]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.resolveFieldValue(AutowiredAnnotationBeanPostProcessor.java:709) ~[spring-beans-6.0.6.jar:6.0.6]
... 34 common frames omitted
Caused by: java.lang.IllegalArgumentException: Not a managed type: class org.randomcraft.PlayerDataAPI.classes.instances.DRStat
at org.hibernate.metamodel.model.domain.internal.JpaMetamodelImpl.managedType(JpaMetamodelImpl.java:181) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
at org.hibernate.metamodel.model.domain.internal.MappingMetamodelImpl.managedType(MappingMetamodelImpl.java:496) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
at org.hibernate.metamodel.model.domain.internal.MappingMetamodelImpl.managedType(MappingMetamodelImpl.java:99) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
at org.springframework.data.jpa.repository.support.JpaMetamodelEntityInformation.<init>(JpaMetamodelEntityInformation.java:77) ~[spring-data-jpa-3.0.3.jar:3.0.3]
at org.springframework.data.jpa.repository.support.JpaEntityInformationSupport.getEntityInformation(JpaEntityInformationSupport.java:69) ~[spring-data-jpa-3.0.3.jar:3.0.3]
at org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getEntityInformation(JpaRepositoryFactory.java:246) ~[spring-data-jpa-3.0.3.jar:3.0.3]
at org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getTargetRepository(JpaRepositoryFactory.java:211) ~[spring-data-jpa-3.0.3.jar:3.0.3]
at org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getTargetRepository(JpaRepositoryFactory.java:194) ~[spring-data-jpa-3.0.3.jar:3.0.3]
at org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getTargetRepository(JpaRepositoryFactory.java:81) ~[spring-data-jpa-3.0.3.jar:3.0.3]
at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:317) ~[spring-data-commons-3.0.3.jar:3.0.3]
at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.lambda$afterPropertiesSet$5(RepositoryFactoryBeanSupport.java:279) ~[spring-data-commons-3.0.3.jar:3.0.3]
at org.springframework.data.util.Lazy.getNullable(Lazy.java:245) ~[spring-data-commons-3.0.3.jar:3.0.3]
at org.springframework.data.util.Lazy.get(Lazy.java:114) ~[spring-data-commons-3.0.3.jar:3.0.3]
at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.afterPropertiesSet(RepositoryFactoryBeanSupport.java:285) ~[spring-data-commons-3.0.3.jar:3.0.3]
at org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean.afterPropertiesSet(JpaRepositoryFactoryBean.java:132) ~[spring-data-jpa-3.0.3.jar:3.0.3]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1808) ~[spring-beans-6.0.6.jar:6.0.6]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1758) ~[spring-beans-6.0.6.jar:6.0.6]
... 44 common frames omitted```
</details>
# 答案1
**得分**: 1
关系数据库没有直接的方法将类层次结构映射到数据库表格。为了解决这个问题,JPA规范提供了几种策略:
- MappedSuperclass – 父类,不能是实体。
- Single Table - 不同类的实体与共同祖先放置在同一表中。
- Joined Table – 每个类有自己的表,查询子类实体需要连接这些表格。
- Table per Class – 类的所有属性都在自己的表格中,因此不需要连接。
每种策略都会导致不同的数据库结构。
我假设你为每个子类有一个单独的表。在你的情况下,(第一个)子类是表 *some_data*,具有列 *uuid*(作为主键)和其他列。
**使用MappedSuperclass注解的解决方案**:
@MappedSuperclass
public class ParentSuperClass {
@Id
@Column(name = "uuid", unique = true, nullable = false)
private String UUID;
// 更多字段
}
@Entity
@Table(name = "some_data")
public class ChildStat extends ParentStat {
// 字段
}
(获取器、设置器、构造函数不是问题的一部分)
<details>
<summary>英文:</summary>
Relational databases don't have a straightforward way to map class hierarchies onto database tables. To address this, the JPA specification provides several strategies:
- MappedSuperclass – the parent classes, can't be entities.
- Single Table - The entities from different classes with a common
ancestor are placed in a single table.
- Joined Table – Each class has its table, and querying a subclass
entity requires joining the tables.
- Table per Class – All the properties of a class are in its table, so
no join is required.
Each strategy results in a different database structure.
I assume that you have a separate table for each child. In your case the (first) child is the table *some_data* with a column *uuid* (as primary key) and other columns.
**The solution** with MappedSuperclass annotation:
@MappedSuperclass
public class ParentSuperClass {
@Id
@Column(name = "uuid", unique = true, nullable = false)
private String UUID;
// More fields
}
@Entity
@Table(name = "some_data")
public class ChildStat extends ParentStat {
// Fields
}
(Getters, setters, constructors not part of the question)
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论