【问题标题】:Handling entities inheritance spring boot处理实体继承spring boot
【发布时间】:2019-04-06 11:52:10
【问题描述】:

我正在使用这个tutorial 来处理实体继承。我有扩展用户实体的个人和公司实体。

@Entity
@Inheritance
public abstract class User { 

@Id
private long id;

@NotNull
private String email;

// getters and settres
}

@Entity
public class Person extends User { 
private int age;
// getters and settres and other attributs
}

@Entity
public class Company extends User { 
private String companyName;
// getters and settres and other attribut
}

然后是扩展 UserBaseRepository 的 UserRpository、PersonRepository 和 Company Repository。

@NoRepositoryBean
public interface UserBaseRepository<T extends User> 
extends CrudRepository<T, Long> {

public T findByEmail(String email);

}

@Transactional
public interface UserRepository extends UserBaseRepository<User> { }

@Transactional
public interface PersonRepository extends UserBaseRepository<Person> { }

@Transactional
public interface CompanyRepository extends UserBaseRepository<Company> { }

问题是当调用 personRepository.findAll() 来获取所有人时,结果我也得到了公司。

【问题讨论】:

  • 我从教程中克隆了项目,一切正常。 Hibernate 生成的 SQL 看起来如何?你用的是什么 Spring 版本?

标签: spring spring-boot jpa spring-data-jpa spring-data


【解决方案1】:

您的问题在于 JPA 需要的“鉴别器”列。您正在使用 @Inheritance 注释,默认情况下将使用 InheritanceType.SINGLE_TABLE 策略。这意味着以下内容:

  1. 您继承的实体Person 和Company 将进入一个表。
  2. JPA 将需要一个鉴别器来区分实体类型。

我执行了以下操作以使其适用于您的用例:

实体:

@Inheritance
@Entity
@Table(name = "user_table")
public abstract class User {

    @Id
    private long id;

    @NotNull
    @Column
    private String email;

    public long getId() {
        return id;
    }

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

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
}

@Entity
public class Company  extends User {

    @Column(name = "company_name")
    private String companyName;

    public String getCompanyName() {
        return companyName;
    }

    public void setCompanyName(String companyName) {
        this.companyName = companyName;
    }
}

@Entity
public class Person extends User {

    @Column
    private int age;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

数据库架构:

-- user table
create table user_table (
  id BIGINT         NOT NULL PRIMARY KEY,
    email             VARCHAR(50) NOT NULL,
    age               INT,
    company_name      VARCHAR(50),
    dtype             VARCHAR(80) -- Discriminator
);

一些测试数据:

insert into user_table(id, dtype, age, email) values
(1,'Person', 25, 'john.doe@email.com'),
(2,'Person',22, 'jane.doe@email.com');

insert into user_table(id, dtype, company_name, email) values
(3,'Company','Acme Consultants', 'acme@company.com'),
(4,'Company', 'Foo Consultants', 'foo@company.com');

存储库:

@NoRepositoryBean
public interface UserBaseRepository<T extends User> extends CrudRepository<T, Long> {

    T findByEmail(String email);
}

@Transactional
public interface PersonRepository extends UserBaseRepository<Person> {

}

@Transactional
public interface CompanyRepository extends UserBaseRepository<Company> {

}

JUnit 测试:

public class MultiRepositoryTest extends BaseWebAppContextTest {

    @Autowired
    private PersonRepository personRepository;

    @Autowired
    private CompanyRepository companyRepository;

    @Test
    public void testGetPersons() {
        List<Person> target = new ArrayList<>();
        personRepository.findAll().forEach(target::add);
        Assert.assertEquals(2, target.size());
    }
    @Test
    public void testGetCompanies() {
        List<Company> target = new ArrayList<>();
        companyRepository.findAll().forEach(target::add);
        Assert.assertEquals(2, target.size());
    }

}

以上测试通过。这表明 JPA 现在正确地利用了鉴别器来检索所需的记录。

有关您问题的 JPA 相关理论,请参阅link。

【讨论】:

  • @Achraf 如果这对你有用,你能继续接受这个作为答案吗?
猜你喜欢
  • 1970-01-01
  • 2020-09-22
  • 2015-02-17
  • 2022-12-11
  • 2019-03-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-31
相关资源
最近更新 更多