如何使用 Spring Data 中相关实体的集合?
Posted
技术标签:
【中文标题】如何使用 Spring Data 中相关实体的集合?【英文标题】:How to work with Collection of related entities in SpringData? 【发布时间】:2015-05-08 17:13:21 【问题描述】:我对与数据相关的技术还很陌生,并且遇到了很多问题。我的代码与 Spring Data Neo4j 相关,但我认为这个问题也可能与其他框架相关(如 JPA 实现)。
为了简单起见,假设我有两个相关的实体
@NodeEntity public class A @RelatedTo Set<B> bs /* Other fields, getters and setters*/
@NodeEntity public class B @RelatedTo A a; /* Other fields, getters and setters*/
两个@Repository 来访问它们
@Repositoty
public interface ARepository extends CRUDRepository<A> /* The usual methods based on name */
@Repositoty
public interface BRepository extends CRUDRepository<B> /* The usual methods based on name */
以及服务层上的两个接口
@Service
public interface AService /* Some useful methods such as CRUD operations*/
@Service
public interface BService /* Some useful methods such as CRUD operations*/
显然,这两个接口都有一个类,用于实现所使用的特定数据库的方法(在本例中为AServiceNeo4j
和BServiceNeo4j
)
好的,在所有这些样板代码之后,这里是真正的问题:
-
首先,我必须在哪里初始化
bs
?我见过很多人在声明字段时直接在 POJO 类中执行此操作(private Set<B> bs = new HashSet<B>();
)。这是一个很好的解决方案吗?它对性能没有负面影响吗?更一般地说,这个解决方案的优缺点是什么,而不是例如在 @Service
类上做它(就像我下面的代码)?
为了向集合中添加一个元素,我是否应该始终获取整个集合,然后在其上调用添加并最终存储/更新实体?还是有更简洁的方法可以避免将整个集合加载到内存中?
在我的服务层上使用addB()
方法是否有意义(再次,如下面的示例)?我还没有看到这个解决方案;相反,在某些示例中,我看到直接在 POJO 类中声明了此方法(因此是 addB(B b)
方法)。在其他示例中,我根本没有看到 addB()
方法;相反,业务逻辑只是调用a.getBs().add(new B())
。最佳解决方案是什么?为什么?
我提出的解决方案是这样的
@Service
public class AServiceNeo4j
/* The other usual methods based on name */
public void addB(A a, B b)
// Start transaction, start try block
if (a.getBs() == null)
a.setBs(new HashSet<B>() );
a.getBs().add(b);
// Store a, add catch and finally blocks
所以,从我的业务逻辑来看,我可以这样做:
A a = new A();
AService aService = // get the service bean from the applicationContext
aService.create(a);
B b = new B();
aService.addB(a, b);
相对于
A a = new A();
AService aService = // get the service bean from the applicationContext
aService.create(a);
B b = new B();
a.getB(s).add(b); // To work, the set should be instantiated in the POJO class (see point 1)
aService.update(a);
这两种解决方案的优势是什么?建议的方法是什么?
此外,对于这两种解决方案,框架不会自动更新对象。我的意思是,对于第一个解决方案,调用 a.getBs().size()
返回 0(或 null,取决于 POJO 类的实现)。调用b.getA()
的第二个解决方案也会出现同样的问题,
为了使这些方法正常工作,我必须从数据存储中检索本地对象以获得更新的值。类似的东西
a = aService.find(a); // or aService.fetch(a);
a.getBs().size();
或
b = bService.find(b); // or bService.fetch(b);
b.getA();
这是为什么?不应该由底层框架自动完成吗?如果不是,这是标准的处理方式吗?
【问题讨论】:
【参考方案1】:关于在哪里初始化集合,我采用了一个很好的做法,在声明字段时在@NodeEntity
中执行此操作(private Set<B> bs = new HashSet<B>();
)有一些 spring-data-neo4j 的示例在此完成方式。见example。
要将元素添加到Collection
,您可以考虑在同一个 POJO 中添加一个方法来执行此操作。示例(请记住 set 已经初始化)
@NodeEntity
public class A
@RelatedTo
Set<B> bs = new HashSet<>();
public void addB(B b)
bs.add(b);
所以,在你的服务层,你可以直接找到实体A
,然后添加它B
。
然后,如果您希望框架能够自动获取集合,除了@Related
,您还需要添加注解@Fetch
。示例:
@Fetch
@RelatedTo
Set<B> bs = new HashSet<>();
对于那些从 spring-data-neo4j 开始的人来说是个好问题。我也一直在为这样的问题而苦苦挣扎。我将等待更多答案,希望其他人可以分享他们的经验。
希望对你有帮助。
【讨论】:
感谢您的分享。好吧,阻止我在 POJO(或 JabaBean,fwiw)中添加 add 方法的原因是它不再是 POJO。 OTOH,阻止我直接初始化集合的事情是对性能的潜在负面影响。您如何看待这些要点? 我也有同样的疑问。,。但最后我采用了它,因为在我的用例中,POJO 中的初始化对性能影响不大(主要读取)。无论如何,我会等待其他回复。谢谢以上是关于如何使用 Spring Data 中相关实体的集合?的主要内容,如果未能解决你的问题,请参考以下文章
无法使用 Spring Data JPA / Hibernate 在事务中两次保存具有不可变集合的实体
学习Spring-Data-Jpa---可嵌入对象和元素集合的使用
Spring Data JPA Repository:如何有条件地获取子实体