Kotlin с jooq и писать таблицы моделей вручную без генерации кода

Aharon Bar-El спросил: 12 мая 2018 в 04:38 в: sql

Я экспериментирую с 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';

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

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

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

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

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

1 ответ

Есть решение
Lukas Eder ответил: 13 мая 2018 в 12:03

Во-первых, несколько советов о нежелании использовать генерацию кода:

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

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

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

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

Я написал более длинное сообщение в блоге об этой теме.

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

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)

ожидаемый оператор из этого кода is: [...]

Ну, это зависит от того, что 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, состоит в том, что модель данных является динамической, то есть неизвестной во время компиляции. В противном случае вы просто будете повторять тонны работы, которые генератор кода уже делает для вас автоматически. И, как уже упоминалось ранее, вы будете иметь гораздо больше работы позже, когда вы начнете мигрировать вашу схему.

Aharon Bar-El ответил: 14 мая 2018 в 09:37
спасибо за ваш совет и полностью ответили на вопрос. Теперь я могу лучше понять силу генерации кода JOOQ и его важность.
Ori Popowski ответил: 18 мая 2018 в 03:01
@LukasEder, что было бы способом решить проблему без генерации кода? Выполнение .as(…) с квалифицированным именем в предложении on не работает, поскольку оно помещает обратные ссылки вокруг псевдонимов.
Lukas Eder ответил: 19 мая 2018 в 06:21
@OriPopowski: Не могли бы вы задать новый вопрос с более подробной информацией?