使用Java Generics的Hibernate Mapping异常

时间:2016-01-06 16:14:29

标签: java spring hibernate generics spring-boot

我正在使用hibernate和泛型来实现某些功能。这里我有两个实体Country和CountryTrans。 CountryTrans代表Country的不同翻译(不同的名称)。我正在为这个项目使用Spring Boot。

我有一个包含Id的顶级课程。

@MappedSuperclass
public abstract class AbstractEntity {

    private Long id;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }
}

然后是包含翻译类型的MultiLingualObject泛型类。

@MappedSuperclass
public abstract class MultiLigualObject<TYPE extends TranslationObject>
        extends AbstractEntity {

    protected List<TYPE> transInfo = new ArrayList<>();

    public abstract List<TYPE> getTransInfo();

    public void setTransInfo(List<TYPE> transInfo) {
        this.transInfo = transInfo;
    }
}

TranslationObject类表示实体翻译。

@MappedSuperclass
public abstract class TranslationObject extends AbstractEntity {

    private String langCode;

    @Column(name = "lang_code")
    public String getLangCode() {
        return langCode;
    }

    public void setLangCode(String langCode) {
        this.langCode = langCode;
    }
}

最后是Country class ..

@Entity
@Table(name = "country")
public class Country extends MultiLigualObject<CountryTrans> {

    private String countryCode;
    private String alternateCode;

    @Column(name = "country_code", nullable = false, length = 2)
    public String getCountryCode() {
        return this.countryCode;
    }

    public void setCountryCode(String countryCode) {
        this.countryCode = countryCode;
    }

    @Column(name = "alternate_code", length = 3)
    public String getAlternateCode() {
        return this.alternateCode;
    }

    public void setAlternateCode(String alternateCode) {
        this.alternateCode = alternateCode;
    }

    @OneToMany(fetch = FetchType.EAGER, mappedBy = "country")
    @Override
    public List<CountryTrans> getTransInfo() {
        return this.transInfo;
    }
}

和CountryTrans课程。

@Entity
@Table(name = "country_trans")
public class CountryTrans extends TranslationObject {

    private String name;

    private Country country;

    @Column(nullable = false)
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @ManyToOne
    @JoinColumn(name = "country_id")
    public Country getCountry() {
        return country;
    }

    public void setCountry(Country country) {
        this.country = country;
    }
}

为了测试这个,我写了一个简单的测试用例。

    @Test
    public void testCountry() throws Exception {
        Country country = countryRepository.findByCountryCode("AD");

    }

当我运行此测试用例时,它会给出以下异常。

Caused by: javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.persistenceException(EntityManagerFactoryBuilderImpl.java:1249)
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.access$600(EntityManagerFactoryBuilderImpl.java:120)
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:860)
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:850)
    at org.hibernate.boot.registry.classloading.internal.ClassLoaderServiceImpl.withTccl(ClassLoaderServiceImpl.java:425)
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:849)
    at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:60)
    at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:343)
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:318)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1637)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1574)
    ... 43 more
Caused by: org.hibernate.MappingException: Could not determine type for: java.util.List, at table: country, for columns: [org.hibernate.mapping.Column(trans_info)]
    at org.hibernate.mapping.SimpleValue.getType(SimpleValue.java:349)
    at org.hibernate.mapping.SimpleValue.isValid(SimpleValue.java:322)
    at org.hibernate.mapping.Property.isValid(Property.java:241)
    at org.hibernate.mapping.PersistentClass.validate(PersistentClass.java:496)
    at org.hibernate.mapping.RootClass.validate(RootClass.java:270)
    at org.hibernate.cfg.Configuration.validate(Configuration.java:1360)
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1851)
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:857)
    ... 51 more

一些基本搜索给出了这是字段级访问与属性访问的问题。但在这里,我在属性级访问中实现了这一点。但不确定为什么会失败。有什么想法吗?

更新

添加CountryRepository

@Repository
public interface CountryRepository extends JpaRepository<Country, Long> {

    Country findByCountryCode(String countryCode);

}

更新 - SQL脚本

CREATE TABLE country (
  id bigint(20) NOT NULL AUTO_INCREMENT,
  alternate_code varchar(3) DEFAULT NULL,
  country_code varchar(2) NOT NULL,
  PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

CREATE TABLE country_trans (
  id bigint(20) NOT NULL AUTO_INCREMENT,
  lang_code varchar(255) DEFAULT NULL,
  country_id bigint(20) DEFAULT NULL,
  name varchar(255) DEFAULT NULL,
  PRIMARY KEY (id),
  CONSTRAINT FK_COUNTRY_TRAN_ID FOREIGN KEY (country_id) REFERENCES country (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

1 个答案:

答案 0 :(得分:1)

Hibernate(或JPA)将使用该类的所有属性,除非您使用@Transient专门标记它们。它试图弄清楚db transInfo中的哪个列映射到。默认情况下,在Table中查找与参数(transInfo)同名的列,但无法找到它。你可以通过告诉它忽略参数来解决这个问题。

示例:

@Transient
private List<CountryTrans> transInfo;