作为上面的图块,我一直在尝试与neo4j-ogm和kotlin一起工作而没有成功。如果我尝试访问我的数据,Neo4j会引发异常,“类xxxx不是有效的实体”。
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不是有效的实体'类的进一步帮助。
注意:我也尝试过在没有pram构造函数的情况下打开movie类,但是id ddnt都可以帮助。另一个尝试是更改neo4j-ogm的版本,所以我测试了2.1.5、3.0.1和3.1.2。没有成功
答案 0 :(得分:5)
编辑:没有说明的超级简短答案是:在您的示例中,您为类扫描配置了错误的程序包。您可以使用val sessionFactory = SessionFactory(configuration, "test.movies.domain")
打开会话,但是需要根据模型的程序包声明val sessionFactory = SessionFactory(configuration, "com.asofttz.micros.administrator.users.testmodels")
进行会话。但除此之外,请参阅我的较长版本以获取一些最佳做法和说明:
在此处找到完整可行的示例作为要点: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问题。
答案 1 :(得分:2)
OGM需要打开类并具有无参数构造函数。默认情况下,Java中的类具有这些特征,但是Kotlin中没有。
您可以将类标记为打开,并手动添加默认构造函数,也可以使用'no-args'和'kotlin-spring'gradle插件。这是一个sample application,它使用Kotlin,Spring Data SDN和OGM。注意在构建文件中,我们有:
noArg {
annotation("org.neo4j.ogm.annotation.NodeEntity")
annotation("org.neo4j.ogm.annotation.RelationshipEntity")
annotation("org.springframework.data.neo4j.annotation.QueryResult")
}
与手动添加默认构造函数相同,但是:
作为替代方案,您可以使用螺栓驱动器并手动映射查询结果。如果您有针对特定用例的自定义查询(例如,具有高流量和精心调整查询的应用程序),这是一个很好的选择。
这是sample application,显示了螺栓驱动器directly的用法。