【问题标题】:How to support @RelatedTo like cross-store persistence with spring-data-neo4j-cross-store?如何使用 spring-data-neo4j-cross-store 支持 @RelatedTo 之类的跨存储持久性?
【发布时间】:2013-09-19 13:35:54
【问题描述】:

我正在尝试将 neo4j 跨存储持久性用于某种设置的数据结构。在 jpa 和 neo4j 之间的边界处,它包含一个引用 jpa 实体的 NodeEntity。因此,neo4j 对象仅包含 jpa-object 的 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 添加过滤器?我不知何故找不到任何东西。或者是否有可能在弹簧数据甚至弹簧级别进行过滤,这可能会有所帮助?

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

【问题讨论】:

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


    【解决方案1】:

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

    我使用 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
    }
    

    更简单的转换器之一是从 object 到 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”风格的关系。

    欢迎提出意见和想法。

    【讨论】:

      猜你喜欢
      • 2015-09-04
      • 1970-01-01
      • 2015-09-04
      • 2012-04-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-16
      • 1970-01-01
      相关资源
      最近更新 更多