0

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

在 mongodb 跨存储持久性和 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 的 neo4j 对象具有相同 ID 的 jpa 表。

现在,在我看来,实现这样的事情的一种可行方法是拦截从 neo4j 中的检索和保存,例如:

  • 当加载 jpa 对象时,通过从 neo4j id 字段读取并将 jpa 对象注入(neo4j 瞬态)字段来加载
  • 保存时 jpa 对象被保存并且 id 被保存到 neo4j id 字段

那么我对 sping-data-neo4j 的能力有什么误解吗?

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

有没有办法向 spring-data-neo4j 添加过滤器?我不知何故找不到任何东西。或者是否有可能在弹簧数据甚至弹簧级别进行过滤,这可能会有所帮助?

我不完全是春季专家,所以任何提示都可能会有所帮助。

4

1 回答 1

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 转换。为此,我定义了一个特征,该特征将 JPA @Entity 定义为具有 Long id:

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)
  }
}

另一方面,我必须定义一个工厂以允许 EntityManager 的 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)
  }
}

最后我不得不在 spring 上下文中注册这些转换器:

<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”风格的关系。

欢迎评论和想法。

于 2013-09-20T15:02:02.563 回答