Spring Data JPA中处理实体继承的最佳方法

50

我有三个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,为这些实体编写repositories类的最佳方法是什么?
我知道我可以编写以下内容:
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 操作。

请告诉我可能的解决方案。


您可以编写公共抽象的A findByName(String name)方法,这样所有的子类都必须实现此方法。 - sven.kwiotek
@s.kwiotek,但我不想实现这样的方法(Spring Data JPA会为我完成,用一些魔法 :)).. 我只想在一个地方定义它,比如在 ARespository 中.. - Andrea
我在使用存储库时发现一个问题,即实体中的继承关系并不会影响存储库的继承关系。与香蕉是“水果”的关系不同,香蕉盒子并不是“水果篮子”。所以说。我更成功地通过组合使BananaRepo使用FruitRepo,仅用于查询的SELECT部分和刚刚实例化的香蕉的基本水果特性的填充。不过你需要检查一下这是否适用于Spring。 - Timo
1个回答

65

我使用了Netgloo博客中此文章中描述的解决方案。

其思路是创建一个类似以下的通用存储库类:

@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> 
{ /* ... */ }

1
在这个例子中,您可以使用存储库B来设置属于类A的属性,该类由类B扩展?我想使用这样的系统通过spring-data-rest控制器更新B。 - ALM
@ALM 我相信你能做到。你试过了吗? - Andrea
是的,我现在就要尝试。实际上,我正在考虑如何设置它,但我认为我会先创建一个非常简单的测试,然后运行它来查看结果。我读了另一篇文章,在那之后,我相信它应该继承存储库A中的内容,然后可以被B使用。A也将被设置为只读。 - ALM
1
@ALM,你找到了合适的解决方案吗?我也有一个类似的情况,在这种情况下,我想要子类库用于写入,而父类库仅用于读取,例如GET ALL(包括子实体)。我还想以spring-data-rest的方式实现它,有办法吗? - Soumitri Pattnaik

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接