【问题标题】:Best way of handling entities inheritance in Spring Data JPA在 Spring Data JPA 中处理实体继承的最佳方式
【发布时间】:2015-02-17 01:47:20
【问题描述】:

我有三个 JPA 实体ABC,其层次结构如下:

    A
    |
+---+---+
|       |
C       B

即:

@Entity
@Inheritance
public abstract class A { /* ... */ }

@Entity
public class B extends A { /* ... */ }

@Entity
public class C extends A { /* ... */ }

使用 Spring Data JPA,为此类实体编写 存储库 类的最佳方法是什么?

我知道我可以写这些:

public interface ARespository extends CrudRepository<A, Long> { }

public interface BRespository extends CrudRepository<B, Long> { }

public interface CRespository extends CrudRepository<C, Long> { }

但是如果在A 类中有一个字段name,我在ARepository 中添加了这个方法:

public A findByName(String name);

我在其他两个仓库中也要写这样的方法,这有点烦人..有没有更好的方法来处理这种情况?

我想知道的另一点是 ARespository 应该是一个只读存储库(即扩展 Repository 类),而其他两个存储库应该公开所有 CRUD 操作。

让我知道可能的解决方案。

【问题讨论】:

  • 你可以写public abstract A findByName(String name),所以所有子类都必须实现这个方法。
  • @s.kwiotek 但我不想实现这样的方法(Spring Data JPA 为我做这件事,有一些魔力:)).. 我只会在一个地方定义它,比如ARespository..
  • 我在存储库中发现的一件事是实体中的继承并不决定存储库中的继承。 Banana 是“一种”水果,而 BananaBox 不是 FruitBasket。可以这么说。我通过 composition 让 BananaRepo 使用 FruitRepo 取得了更大的成功,仅在 (A) SELECT 部分访问它查询,并 (B) 填充刚刚实例化的 Banana 的基本 Fruit-properties。不过,您必须检查 Spring 是否可以做到这一点。

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


【解决方案1】:

我使用了 Netgloo 博客中 this post 中描述的解决方案。

这个想法是创建一个 generic 存储库类,如下所示:

@NoRepositoryBean
public interface ABaseRepository<T extends A> 
extends CrudRepository<T, Long> {
  // All methods in this repository will be available in the ARepository,
  // in the BRepository and in the CRepository.
  // ...
}

那我可以这样写三个仓库:

@Transactional
public interface ARepository extends ABaseRepository<A> { /* ... */ }

@Transactional
public interface BRepository extends ABaseRepository<B> { /* ... */ }

@Transactional
public interface CRepository extends ABaseRepository<C> { /* ... */ }

此外,要获得ARepository 的只读存储库,我可以将ABaseRepository 定义为只读:

@NoRepositoryBean
public interface ABaseRepository<T> 
extends Repository<T, Long> {
  T findOne(Long id);
  Iterable<T> findAll();
  Iterable<T> findAll(Sort sort);
  Page<T> findAll(Pageable pageable);
}

并且从 BRepository 扩展 Spring Data JPA 的 CrudRepository 以实现读/写存储库:

@Transactional
public interface BRepository 
extends ABaseRepository<B>, CrudRepository<B, Long> 
{ /* ... */ }

【讨论】:

  • 在这个例子中,您可以使用存储库 B 来设置属于由 B 类扩展的 A 类的属性吗?我想使用这样的系统通过 spring-data-rest 控制器更新 B。
  • @ALM 我很确定你能做到。你试过了吗?
  • 是的,我现在就要尝试。我实际上正在讨论我想如何设置它,但我想我会先创建一个非常简单的测试,然后运行它来查看。我阅读了另一篇文章,之后我相信它应该继承存储库 A 的内容,然后可以被 B 使用。A 也将设置为只读
  • @ALM 您找到合适的解决方案了吗?我也有类似的情况,我希望子类存储库用于写入,父类存储库仅用于读取,例如 GET ALL(包括子实体)。我也想按照spring-data-rest的方式来做,有没有办法?
猜你喜欢
  • 1970-01-01
  • 2019-04-17
  • 2019-04-06
  • 2020-09-22
  • 2019-10-03
  • 1970-01-01
  • 2019-11-05
  • 2014-03-25
  • 1970-01-01
相关资源
最近更新 更多