如何使用SpringData中相关实体的集合?

时间:2015-05-08 17:13:21

标签: spring orm neo4j spring-data spring-data-neo4j

我对数据相关的技术很陌生,而且我在很多问题上苦苦挣扎。我的代码与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

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

  1. 首先,我在哪里初始化bs?在声明字段(private Set<B> bs = new HashSet<B>();)时,我已经看到许多人直接在POJO类中执行此操作。这是一个好的解决方案吗?它不会对性能产生负面影响吗?更一般地说,这个解决方案的优点和缺点是什么,而不是,例如,在@Service类(如下面的代码)上执行此操作?
  2. 为了向集合中添加元素,我应该总是获取整个集合,然后在其上调用add并最终存储/更新实体吗?或者是否有更简洁的方法可以避免将整个集合加载到内存中?
  3. 在我的服务层上使用addB()方法是否有意义(再次,如下面的示例)?我还没有看到这个解决方案;相反,在某些例子中,我看到这个方法直接在POJO类中声明(所以addB(B b)方法)。在其他示例中,我根本没有看到addB()方法;相反,业务逻辑只调用a.getBs().add(new B())。什么是最佳解决方案?为什么?
  4. 我建议的解决方案是那样的

    @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 个答案:

答案 0 :(得分:1)

关于初始化集合的位置,我已经采用了@NodeEntity声明字段(private Set<B> bs = new HashSet<B>();时的良好做法。有一些弹簧数据示例 - neo4j以这种方式完成。请参阅example

要向Collection添加元素,您可以考虑在同一个POJO中添加方法来执行此操作。示例(请记住,集已经初始化)

@NodeEntity
public class A {

   @RelatedTo
   Set<B> bs = new HashSet<>();

   public void addB(B b) {
      bs.add(b);
   }
}

因此,在您的服务层中,您可以直接找到实体A,然后添加B

然后,如果您希望框架能够自动获取集合,则除了@Fetch之外,还需要添加注释@Related。例如:

   @Fetch
   @RelatedTo
   Set<B> bs = new HashSet<>();

对于那些以spring-data-neo4j开头的人来说是个好问题。我也一直在努力解决这些问题。我会等待更多的答案,希望其他人可以分享他们的经验。

希望它有所帮助。