Kotlin с Jooq и писать таблицы моделей вручную без генерации кода - PullRequest
0 голосов
/ 05 июня 2018

Я экспериментирую с jOOQ и Kotlin и видел несколько уроков и документов, и это выглядит действительно хорошо.

Но если есть что-то очень раздражающее в jOOQ, это генерация кода.Это кажется слишком сложным, и в конечном итоге невозможно поддерживать.Я решил создать свои собственные модели таблиц (аналогично тому, как работает hibernate).

Я создал две модели таблиц:

Пользователь

data class User(
    val id: String = UUID.randomUUID().toString(),
    val name: String,
    val email: String,
    val password: String? = null
) {
    companion object {
        val TABLE: Table<Record> = DSL.table("user")
        val ID: Field<String> = DSL.field("id", String::class.java)
        val USER_NAME: Field<String> = DSL.field("user_name", String::class.java)
        val EMAIL: Field<String> = DSL.field("email", String::class.java)
        val PASSWORD: Field<String> = DSL.field("password", String::class.java)
    }
}

Последователи

data class Followers(
    val id: String,
    val followerId: String,
    val userId: String
) {
    companion object {
        val TABLE: Table<Record> = DSL.table("followers")
        val ID: Field<String> = DSL.field("id", String::class.java)
        val FOLLOWER_ID: Field<String> = DSL.field("follower_id", String::class.java)
        val USER_ID: Field<String> = DSL.field("user_id", String::class.java)
    }
}

Когда я выполнял некоторые тривиальные операторы SQL, и они отлично работали, но когда я пробовал следующий оператор, я получал исключение.

return dsl.select().from(u.TABLE)
            .rightJoin(f.TABLE).on(u.ID.eq(f.FOLLOWER_ID))
            .where(u.ID.eq(id)).fetch().into(User::class.java)

Ожидаемое утверждение из этого кода:

select *
from user u
right outer join followers f
on u.id = f.follower_id
where u.id = 'e30919bf-5f76-11e8-8c96-701ce7e27f83';

Но утверждение, которое я получил из этого кода:

select *
from user
  right outer join followers
  on id = follower_id
where id = 'e30919bf-5f76-11e8-8c96-701ce7e27f83'

И, конечно, это дает мне (по праву) ошибку Столбец 'id' в выражении where является неоднозначным

Возникает несколько вопросов:

  1. Есть ли лучший способ объявить модель таблицы без генерации кода.
  2. Почему DSL select не преобразуется в правильный оператор SQL?Что я делаю не так?

1 Ответ

0 голосов
/ 06 июня 2018

Прежде всего, несколько советов о вашем нежелании использовать генерацию кода:

мне кажется слишком сложным, и в конечном итоге его невозможно поддерживать.Итак, я решил создать свои собственные настольные модели (аналогично тому, как работает Hibernate).

Вы (вероятно) идете по длинному пути боли и страдания.Прежде всего, вам уже сейчас нужно подумать о переносе баз данных, которые лучше всего выполнять с использованием языка DDL вашей базы данных.Это означает, что ваша модель базы данных ваших данных должна быть более важной для вас в долгосрочной перспективе, чем ваша модель клиента.Фактически, ваша модель клиента - это копия модели вашей базы данных, а не то, что вы хотели бы поддерживать самостоятельно.При таком подходе более разумно, чтобы генератор кода генерировал вашу модель клиента из модели базы данных, а не наоборот.

Конечно, Hibernate также облегчает первый подход к клиенту, когда вы начинаете проект.Тем не менее, как только вы перейдете к производству, вам придется перенести вашу базу данных, и тогда эта модель сломается.Сначала вы вернулись в базу данных, и все уже стоит настроить.

Так что нет.Генерация кода может создать некоторую сложность сейчас , но будет гораздо проще поддерживать *1016* в будущем, чем создание собственных таблиц моделей.

Я написал более длинное сообщение в блоге на эту тему, здесь .

Относительно ваших конкретных вопросов:

return dsl.select().from(u.TABLE)
          .rightJoin(f.TABLE).on(u.ID.eq(f.FOLLOWER_ID))
          .where(u.ID.eq(id)).fetch().into(User::class.java)

ожидаемое утверждение из этого кода: [...]

Ну, это зависит от того, что такое u и f.Вы не можете просто переименовать ваши ссылки Kotlin на вашу таблицу и ожидать, что jOOQ узнает, что они значат.Т.е. вы, вероятно, создали ссылки следующим образом:

val u = User.TABLE;
val f = Follower.TABLE;

Если вы создали ссылку таким образом, то две вещи - это одно и то же по идентичности.jOOQ волшебным образом не реконструирует ваш код Kotlin, чтобы выяснить, что вы хотели псевдоним вашего стола.Вы должны сказать jOOQ:

val u = User.TABLE.as("u");
val f = Follower.TABLE.as("f");

Но теперь вы еще не закончили.Вы создали ссылку User.TABLE, используя обычный SQL API , что означает, что среда выполнения jOOQ не имеет представления о столбцах в этой таблице.Вы больше не можете ссылаться на эти столбцы из таблицы с псевдонимами, потому что тип таблицы с псевдонимами для простых таблиц SQL - Table<?>, а не User.

Конечно, вы можете создать TableImpl экземпляров изарегистрируйте все столбцы внутри вашего TableImpl экземпляра - так же, как это делает генератор кода.В этом случае вы будете иметь связанные с ними столбцы таблиц и и сможете безопасно использовать их тип даже с псевдонимными таблицами.

Все это автоматически обрабатывается сгенерированным кодом, который сноваЯ рекомендую использовать с JOOQ.Основная причина, по которой никто не будет использовать генератор кода с jOOQ, заключается в том, что модель данных является динамической, то есть неизвестной во время компиляции.В противном случае вы просто будете повторять тонны работы, которую генератор кода уже выполняет для вас, автоматически.И, как упоминалось ранее, у вас будет намного больше работы, когда вы начнете мигрировать свою схему.

...