如何使用 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*/ 

显然,这两个接口都有一个类,用于实现所使用的特定数据库的方法(在本例中为AServiceNeo4jBServiceNeo4j


好的,在所有这些样板代码之后,这里是真正的问题:

    首先,我必须在哪里初始化bs?我见过很多人在声明字段时直接在 POJO 类中执行此操作(private Set&lt;B&gt; bs = new HashSet&lt;B&gt;();)。这是一个很好的解决方案吗?它对性能没有负面影响吗?更一般地说,这个解决方案的优缺点是什么,而不是例如在 @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&lt;B&gt; bs = new HashSet&lt;B&gt;();)有一些 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:如何有条件地获取子实体

Spring Data:覆盖保存方法

如果使用 Spring Data Repositories (Spring 4),如何从持久性上下文中分离实体

如何使用 Spring Boot 和 Spring Data 访问实体管理器