Neo4j - OGM не бросает сущность в Котлин - PullRequest
0 голосов
/ 31 августа 2018

Как и выше, я безуспешно пытался работать с 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>()
}

Есть ли способ обойти? Есть ли альтернатива для сохранения данных в базе данных Neo4j с помощью kotlin?

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. Нет успеха

Ответы [ 2 ]

0 голосов
/ 04 сентября 2018

Редактировать: Супер короткий ответ без объяснения: В вашем примере вы настраиваете неправильный пакет для сканирования классов. Вы открываете сеанс с val sessionFactory = SessionFactory(configuration, "test.movies.domain"), но это должно быть val sessionFactory = SessionFactory(configuration, "com.asofttz.micros.administrator.users.testmodels"), судя по объявлению пакета ваших моделей. Но кроме того, пожалуйста, посмотрите мою более длинную версию для некоторых лучших практик и объяснений:

Найдите полный и рабочий пример в виде гистограммы здесь: Минимальный пример Kotlin / Gradle для Neo4j OGM

Позвольте мне провести вас через это:

В build.gradle определите плагин компилятора без аргументов как зависимость сценария сборки.

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, должны иметь синтетический конструктор без аргументов.

Я абсолютно согласен с Джаспером в том, что это лучший подход, чем использование по умолчанию всех параметров конструктора класса вашего домена, для справки: kotlin-noarg docs:

Плагин компилятора без аргументов генерирует дополнительный нулевой аргумент конструктор для классов с определенной аннотацией.

Сгенерированный конструктор является синтетическим, поэтому его нельзя вызвать напрямую из Java или Kotlin, но его можно вызвать с помощью отражения.

В отношении классов доменов: классы, отображаемые с помощью Neo4j OGM, не обязательно должны быть окончательными. Но мы не поддерживаем конечные поля и, как таковые, чистых неизменяемых классов. Так обстоят дела сейчас.

Итак, оба класса доменов:

@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 и используйте тот факт, что наши атрибуты больше не являются окончательными, и измените сами поля:

@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, которую вы создали сейчас.

0 голосов
/ 31 августа 2018

OGM требует, чтобы классы были открыты и имели конструктор без аргументов. Классы в Java демонстрируют эти черты по умолчанию, но не в Kotlin.

Вы можете пометить класс как открытый и добавить конструктор по умолчанию вручную, или вы можете использовать плагины gradle 'no-args' и 'kotlin-spring'. Вот пример приложения , в котором используются 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")
}

Что аналогично добавлению конструктора по умолчанию вручную:

  • Код чище
  • Конструктор по умолчанию специально предназначен для использования библиотеками во время выполнения и в противном случае скрыт.

В качестве альтернативы, вы можете использовать болт-драйвер и отобразить результат запроса вручную. Это хороший вариант для случаев, когда у вас есть пользовательские запросы для конкретных случаев использования, таких как приложения с большим трафиком и тщательно настроенными запросами.

Вот пример приложения , показывающий использование болт-драйвера напрямую .

...