【问题标题】:Neo4j - OGM throws not an Entity in KotlinNeo4j - OGM 不会在 Kotlin 中抛出实体
【发布时间】:2019-02-05 23:28:17
【问题描述】:

如上图所示,我一直在尝试使用 neo4j-ogm 和 kotlin,但没有成功。如果我尝试保留我的数据,Neo4j 会抛出异常,“Class xxxx is not a valid Entity”。

package com.asofttz.micros.administrator.users.testmodels

import org.neo4j.ogm.annotation.GeneratedValue
import org.neo4j.ogm.annotation.Id
import org.neo4j.ogm.annotation.NodeEntity
import org.neo4j.ogm.annotation.Relationship

@NodeEntity
class Actor(var name: String = "") {

    @Id
    @GeneratedValue
    open var id: Long? = null

    @Relationship(type = "ACTS_IN", direction = "OUTGOING")
    open val movies = hashSetOf<Movie>()

    fun actsIn(movie: Movie) {
        movies.add(movie)
        movie.actors.plus(this)
    }
}
@NodeEntity
class Movie(var title: String = "", var released: Int = 2000) {

    @Id
    @GeneratedValue
    open var id: Long? = null
    @Relationship(type = "ACTS_IN", direction = "INCOMING")
    open var actors = setOf<Actor>()
}

有办法吗?有没有其他方法可以使用 kotlin 将数据持久化到 Neo4j 数据库?

N:B。我正在使用 kotlin 版本 1.2.60 和 Neo4j-OGM v3.2.1


更新

下面是我的其余代码
import com.asofttz.micros.administrator.users.testmodels.Actor
import com.asofttz.micros.administrator.users.testmodels.Movie
import org.neo4j.ogm.config.Configuration
import org.neo4j.ogm.session.SessionFactory
import java.util.*


object Neo4j {
    val configuration = Configuration.Builder()
            .uri("bolt://localhost")
            .credentials("neo4j", "password")
            .build()

    val sessionFactory = SessionFactory(configuration, "test.movies.domain")

    fun save() {

        val session = sessionFactory.openSession()

        val movie = Movie("The Matrix", 1999)

        session.save(movie)

        val matrix = session.load(Movie::class.java, movie.id)
        for (actor in matrix.actors) {
            println("Actor: " + actor.name)
        }
    }
}

build.gradle 文件如下所示

apply plugin: 'kotlin'
apply plugin: 'application'
apply plugin: "org.jetbrains.kotlin.plugin.noarg"

repositories {
    jcenter()
    mavenCentral()
    maven { url "http://dl.bintray.com/kotlin/ktor" }
    maven { url "https://dl.bintray.com/kotlin/kontlinx" }
}

noArg {
    annotation("org.neo4j.ogm.annotation.NodeEntity")
    annotation("org.neo4j.ogm.annotation.RelationshipEntity")
}

dependencies {
    compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
    compile "io.ktor:ktor:$ktor_version"
    compile "io.ktor:ktor-server-netty:$ktor_version"

    compile project(":asoftlibs:micros:administrator:users:users-jvm")

    compile 'org.neo4j:neo4j-ogm-core:3.1.2'
    compile 'org.neo4j:neo4j-ogm-bolt-driver:3.1.2'
}

kotlin {
    experimental {
        coroutines "enable"
    }
}

compileKotlin {
    kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
    kotlinOptions.jvmTarget = "1.8"
}
sourceCompatibility = "1.8"

我得到了类 'com.asofttz.micros.administrator.users.testmodels.Movie 不是有效实体' 进一步的帮助将不胜感激。

注意:我还尝试在没有婴儿车构造器的情况下打开电影类,但 id ddnt 也有帮助。另一种尝试是更改neo4j-ogm的版本,所以我测试了2.1.5、3.0.1和3.1.2。没有成功

【问题讨论】:

  • 您也可以发布您的实体吗?
  • 我再次编辑了这个问题。包含的实体
  • 如果您将您的班级声明为open class Actor(var name: String = ""),它应该可以工作。或者,您可以使用全开放 gradle 插件(或 kotlin-spring 插件,它是全开放的包装器)
  • @JasperBlues 添加了它。 ddnt 工作。它说'Class class com.asofttz.micros.administrator.users.testmodels.Movie 不是有效的实体类。请检查实体映射。附言。我添加了 allOpen 插件
  • 您能否尝试将var name: String = "" 类型设为可选。电影类也是如此。失败请压缩并发送电子邮件至 jasper@graphaware.com

标签: neo4j kotlin neo4j-ogm


【解决方案1】:

编辑:没有解释的超级简短答案是:在您的示例中,您为类扫描配置了错误的包。您正在使用val sessionFactory = SessionFactory(configuration, "test.movies.domain") 打开会话,但从模型的包声明来看,它必须是val sessionFactory = SessionFactory(configuration, "com.asofttz.micros.administrator.users.testmodels")。但除此之外,请参阅我的加长版以了解一些最佳实践和解释:

在此处找到完整且有效的示例作为 Gist:Minimal Kotlin/Gradle Example for Neo4j OGM

让我带你了解一下:

build.gradle 中,将No-arg compiler plugin 定义为构建脚本依赖项。

buildscript {
    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-noarg:1.2.51"
    }
}

然后使用noArg 块来定义应为哪些类合成无参数构造函数:

noArg {
    annotation("org.neo4j.ogm.annotation.NodeEntity")
    annotation("org.neo4j.ogm.annotation.RelationshipEntity")
}

这意味着:所有使用 @NodeEntity@RelationshipEntity 注释的类都应该有一个合成的无参数构造函数。

我完全同意 Jasper 的观点,即这是比默认域类的所有构造函数参数更好的方法,作为参考,kotlin-noarg 文档:

无参数编译器插件生成一个额外的零参数 具有特定注释的类的构造函数。

生成的构造函数是合成的,所以不能直接调用 来自 Java 或 Kotlin,但可以使用反射调用。

关于域类:Neo4j OGM 映射的类不需要是最终的。但是我们不支持 final 字段,因此不支持纯不可变类。这就是目前的情况。

所以这里是两个域类:

@NodeEntity
class Actor(var name: String) {

    @Id
    @GeneratedValue
    var id: Long? = null

    @Relationship(type = "ACTS_IN", direction = "OUTGOING")
    var movies = mutableSetOf<Movie>()

    fun actsIn(movie: Movie) {
        movies.add(movie)
        movie.actors.add(this)
    }
}

@NodeEntity
class Movie(var title: String, var released: Int) {

    @Id
    @GeneratedValue
    var id: Long? = null
    @Relationship(type = "ACTS_IN", direction = "INCOMING")
    var actors = mutableSetOf<Actor>()
}

请注意,所有字段都是var,而不是val。您可以在此处安全地省略 open 关键字。另请注意,我确实删除了“真实”业务信息的默认参数(此处为标题和发布年份)。

我们必须特别注意这些集合:我删除了显式的hashSetOf,而是使用了mutableSetOf。我们可以使用#add 来改变集合本身。

如果您更喜欢 Kotlin 惯用的方式,请使用 setOf 并利用我们的属性不再是 final 的事实并改变字段本身:

@NodeEntity
class Actor(var name: String) {

    @Id
    @GeneratedValue
    var id: Long? = null

    @Relationship(type = "ACTS_IN", direction = "OUTGOING")
    var movies = setOf<Movie>()

    fun actsIn(movie: Movie) {
        movies += movie
        movie.actors += this
    }
}

@NodeEntity
class Movie(var title: String, var released: Int) {

    @Id
    @GeneratedValue
    var id: Long? = null
    @Relationship(type = "ACTS_IN", direction = "INCOMING")
    var actors = setOf<Actor>()
}

请注意:在您的原始示例中,您有一个类似 movie.actors.plus(this) 的语句。这不会改变集合,而是创建一个新集合,就像集合的+ 运算符所做的那样。

在建模层面:我个人不会在两个方向上映射关系。这迟早会咬你一口,就像它在 JPA/ORM 世界中一样。映射您的逻辑所需的方向并分别执行路径等其他查询。

如果这有帮助,请告诉我。我正在关闭您现在创建的 GH 问题。

【讨论】:

    【解决方案2】:

    OGM 要求类是开放的并且有一个无参数的构造函数。 Java 中的类默认表现出这些特征,但在 Kotlin 中却没有。

    您可以将类标记为打开,并手动添加默认构造函数,或者您可以使用 'no-args' 和 'kotlin-spring' gradle 插件。这是一个使用 Kotlin、Spring Data SDN 和 OGM 的 sample application。注意在我们的构建文件中:

    noArg {
        annotation("org.neo4j.ogm.annotation.NodeEntity")
        annotation("org.neo4j.ogm.annotation.RelationshipEntity")
        annotation("org.springframework.data.neo4j.annotation.QueryResult")
    }
    

    这与手动添加默认构造函数相同,但是:

    • 代码更简洁
    • 默认构造函数专门供库在运行时使用,否则会被隐藏。

    作为替代方案,您可以使用螺栓驱动器并手动映射查询结果。当您有针对特定用例的自定义查询时,这是一个不错的选择 - 例如具有高流量的应用程序和经过仔细调整的查询。

    这是一个sample application,展示了螺栓驱动器directly 的使用。

    【讨论】:

    • 我没有做到这一点,因为响应仍然相同。我已经编辑了我的问题。请注意,我没有使用弹簧。我正在使用开箱即用的 ktor-server
    猜你喜欢
    • 1970-01-01
    • 2021-08-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多