如何使用spring-data-neo4j-cross-store支持@RelatedTo,如跨存储持久性?

时间:2013-09-19 13:35:54

标签: spring neo4j spring-data spring-data-jpa spring-data-neo4j

我正在尝试将neo4j交叉存储持久性用于稍微设置的数据结构。在jpa和neo4j之间的边界处,它包含一个引用jpa实体的NodeEntity。因此neo4j对象只包含jpa-object的id作为参考。

在mongodb跨存储persitence和neo4j持久性的混合语法中,这可能看起来像这样:

@NodeEntity    
public class MyNode {
  @GraphId
  Long id;

  @RelatedTo
  MyEntity entity;

  ... //setters and setters omitted
}

@Entity
public class MyEntity {
  @Id @GeneratedValue
  Long id;

  String name;

  ... //getters and setters omitted
}

使用spring-data-neo4j似乎无法实现这种跨存储持久性。支持的唯一形式似乎是使用@NodeEntity(“partial = true”),它需要一个jpa表,其id与包含jpa id的neo4j对象相同。

现在,在我看来,实现类似这样的东西的可行方法是截取neo4j的检索和保存,例如:

  • 加载jpa对象时,通过读取neo4j id字段并将jpa obejct注入(neo4j transient)字段来加载
  • 保存jpa对象时保存,id保存到neo4j id字段

我对sping-data-neo4j的功能有误吗?

这似乎是一种可行的方法吗?

有没有办法为spring-data-neo4j添加过滤器?我在某种程度上找不到任何东西。或者在弹簧数据甚至弹簧水平上是否有可能有帮助的过滤可能性?

我不是一个春天的专家,所以任何暗示都可能有所帮助。

1 个答案:

答案 0 :(得分:3)

我以某种方式解决了这个问题。

我使用Spring的Converter和ConverterFactory可能来隐式地从我的@Entity对象转换为Long,反之亦然。

@NodeEntity如下所示(代码在Scala中 - 但与Java没有相关的区别):

@NodeEntity
class ImplicitUser {
  @GraphId
  var id: java.lang.Long = _

  @Indexed(indexName="username", indexType=IndexType.FULLTEXT)
  var username : String = _

  @GraphProperty(propertyType = classOf[java.lang.Long])
  var person : Person = _

  override def toString =
    "User %d %s".format(id, username)
}

相关部分是:

  @GraphProperty(propertyType = classOf[java.lang.Long])
  var person : Person = _

因为这告诉neo4j将该字段保持为Long试图找到一个Spring转换器。因此,需要定义Spring转换。为此,我定义了一个特征,它定义了一个具有Long id的JPA @Entity:

trait JpaLongId {
  @Id @GeneratedValue
  var id: Long = -1
}

更简单的转换器就是从对象到Id的那个:

class JpaLongIdToLong extends Converter[JpaLongId, java.lang.Long] {
  def convert(source : JpaLongId) : java.lang.Long = {
    long2Long(source.id)
  }
}

换句话说,我必须定义一个工厂以允许实体管理器的DI:

@Component
class LongToJpaLongIdFactory extends ConverterFactory[java.lang.Long, JpaLongId] {
  def getConverter[T <: JpaLongId](`type`: Class[T]): Converter[java.lang.Long, T] = {
    return new LongToJpaLongId(`type`, em)
  }

  @PersistenceContext
  var em: EntityManager = null
}

class LongToJpaLongId[T <: JpaLongId] extends Converter[java.lang.Long, T] {
  private var `type`: Class[T] = null
  private var em: EntityManager  = null

  def this(`type`: Class[T], em: EntityManager) {
    this()
    this.`type` = `type`
    this.em = em
  }

  def convert(key: java.lang.Long): T = {
    return em.find(`type`, key)
  }
}

最后,我必须在春季环境中注册这些转换器:

<bean id="conversionService"
      class="org.springframework.context.support.ConversionServiceFactoryBean">
    <property name="converters">
        <list>
            <bean class="at.granul.spring.jpa.LongToJpaLongIdFactory"/>
            <bean class="at.granul.spring.jpa.JpaLongIdToLong"/>
        </list>
    </property>
</bean>

就是这样!现在很容易定义这种“RealtedTo”风格的关系。

欢迎评论和想法。