Попытка найти более семантический способ написания Spring Entity на Kotlin - PullRequest
1 голос
/ 28 мая 2019

У меня есть сущность Spring, написанная на Kotlin:

@Entity
class Book(
    @Id
    var id: Long? = null,
    var title: String? = null, // cannot actually be null, immutable
    var isInStock: Boolean? = null, // cannot actually be null
    var description: String? = null,
 )

Все поля должны быть обнуляемыми, потому что Spring должен инициализировать пустые объекты.

Однако это усложняет использование сущностипотому что я всегда должен преобразовывать обнуляемые типы в их не обнуляемые эквивалентыЭто не семантика: я хотел бы реально увидеть, какие поля могут быть обнуляемыми, а какие нет (или могут быть null только в процессе инициализации).

Кроме того, некоторые поля являются изменяемыми, но некоторые никогда не должны изменяться после создания объекта.Было бы неплохо использовать val и var от Kotlin, чтобы сделать это различие.

Итак, я хотел бы поработать со следующим классом:

class BetterBook(
    val id: Long,
    val title: String,
    var isInStock: Boolean,
    var description: String? = null,
 )

Таким образом, этоочень ясно, какие поля являются изменяемыми, а какие могут быть null.

Я размышлял о создании оболочки вокруг Book.У кого-нибудь была похожая мысль?Будет ли это хорошим решением архитектурно?

Ответы [ 3 ]

1 голос
/ 30 мая 2019

На самом деле вы можете делать именно то, что вам нужно: определить класс с val вместо var для неизменяемых свойств, дать им необнуляемые типы и не иметь конструктора по умолчанию. Spring использует Reflection, чтобы получить переменные-члены, лежащие в основе свойств (только для чтения), сгенерированных кодом Kotlin, при установке значений из базы данных. А для конструктора по умолчанию (который ему нужен во время выполнения) есть плагин kotlin-jpa , который автоматически сгенерирует это для вас в скомпилированном коде. Поэтому в основном сохраняйте свой код в точности так, как вы идиоматически его пишете (как вы это делали для BetterBook), и аннотируйте класс с помощью @Entity, но обязательно применяйте этот плагин.

0 голосов
/ 01 июня 2019

Я использую JHipster (или KHipster, его проект Kotlin).Поскольку все сущности генерируются KHipster, я не хочу изменять эти файлы, поскольку все мои изменения будут отменены, когда я заново создаю сущность.После экспериментов с различными решениями я решил добавить дополнительный слой-обертку.

Обертка - это как PR-менеджер для сущности.Он может быть построен из сущности, затем он может быть изменен на уровне обслуживания, и как только настало время его сохранить, оболочка вернет вам обновленную сущность.

Вот так примерно выглядит сущность KHipsterкак:

@Entity
class Agreement(
    @Id
    var id: Long? = null, // should be immuatble
    var description: String? = null, // cannot be null, immutable if `isSigned == true`
    var isSigned: Boolean? = null,
 )

Использование этой сущности напрямую подвержено ошибкам и не очень удобно.Оболочка решает все эти проблемы:

class AgreementWrapper(agreement: Agreement) {
    val id = agreement.id  // NOTICE that we can now use `val` 
    var description: String = agreement.description!! // NOT NULLABLE 
        set(value) {
            if (isSigned == true) throw Exception("A signed agreement cannot be changed!")
            field = value
        }
    var isSigned = agreement.isSigned!!
        set(value) {
            if (isSigned == true && value == false) throw Exception("You cannot undo it!")
            field = value
        }

    val entity: Agreement // This will give us back the updated entity
        get() {
            return Agreement(id, description, isSigned)
        }
}

Кроме того, обертка может также использоваться для создания новых объектов.Добавление значений по умолчанию к сущностям (например, добавление метки времени) также потребует изменения файла, созданного KHipster, но здесь с этим нет проблем.Я просто добавил еще один конструктор в оболочку, которая принимает необходимые параметры и в противном случае использует значения по умолчанию.Он также может иметь дело с проверкой и ведением журнала.

Таким образом, обертки действуют как мост между сущностями и уровнем обслуживания.

0 голосов
/ 29 мая 2019

JPA (не Spring) не требует никаких конструкторов аргументов и изменяемых атрибутов, так что на самом деле вы ничего не можете сделать в этом направлении.

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

Вы можете рассмотреть совершенно другой уровень персистентности, который более гибок, когда дело доходит до конструкторов.Spring Data JDBC может действительно отвечать всем требованиям.Он имеет некоторую поддержку неизменяемых объектов.Он также сильно отличается от JPA, что может быть хорошим или плохим, в зависимости от вашего мнения о JPA.

Прочтите эти две статьи, чтобы получить представление об основных понятиях, стоящих за ним: https://spring.io/blog/2018/09/17/introducing-spring-data-jdbc и https://spring.io/blog/2018/09/24/spring-data-jdbc-references-and-aggregates

...