しおしお

IntelliJのあれやこれや

DomaでOracle12CのIdentity Columnを使ってみた

DomaでOracle12CのIdentity Columnを使う方法です。

DomaのOracleDialectなどなどでは、使うことが出来ないので色々いじってあげる必要があります。

Oracle12C用のDialectを作る

基本は、OracleDialectと同じでいいので継承して作ります。
変更点は、Identity Columnを使えるようにするためにsupportsIdentityでtrueを返します。
また、Statement.getGeneratedKeys()でデータベース側で採番した値を取得したいので、supportsAutoGeneratedKeysでもtrueを返します。

object Oracle12Dialect : OracleDialect() {

    override fun supportsIdentity() = true

    override fun supportsAutoGeneratedKeys() = true
}

Configクラスを作る

getDialectでは、先程作ったOracle12C用のDialect実装を返します。
getCommandImplementorsは、insert時のprepareStatementでprepareStatement(String sql, int[] columnIndexes)を使用するように変更します。
Domaの実装だとIdentity Columnの採番された値ではなく、ROWIDの値がStatement.getGeneratedKeys()で返されてしまうので変更しています。

あとは、接続先の設定などなどをしてあげます。

object AppConfig : Config {

    private val dialect: Dialect = Oracle12Dialect

    override fun getCommandImplementors(): CommandImplementors {
        return object : CommandImplementors {
            override fun createInsertCommand(method: Method, query: InsertQuery): InsertCommand {
                return object : InsertCommand(query) {
                    override fun prepareStatement(connection: Connection): PreparedStatement {
                        return if (query.isAutoGeneratedKeysSupported) {
                            connection.prepareStatement(sql.rawSql, intArrayOf(1))
                        } else {
                            super.prepareStatement(connection)
                        }
                    }
                }
            }
        }
    }

    private val dataSource by lazy {
        val oracleDataSource = OracleDataSource()
        oracleDataSource.user = "siosio"
        oracleDataSource.setPassword("siosio")
        oracleDataSource.url = "...."

        LocalTransactionDataSource(oracleDataSource)
    }

    override fun getTransactionManager(): TransactionManager {
        return LocalTransactionManager(dataSource.getLocalTransaction(jdbcLogger))
    }

    override fun getDataSource(): DataSource = dataSource

    override fun getDialect(): Dialect = dialect
}

Entityを作る

主キーのGeneratedValueをGenerationType.IDENTITYなカラムにしてあげます。

@Entity(immutable = true)
@Table(name = "users")
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    public final Long id;

    public final String name;

    public User(final Long id, final String name) {
        this.id = id;
        this.name = name;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

Daoを作る

@Dao(config = AppConfig.class)
public interface UserDao {

    @Insert
    Result<User> insert(User user);
}

テーブルを作る

idカラムをidentityなカラムにしてあげます。

create table users(
  id number(15) generated always as identity ,
  name varchar2(150 char),
  primary key (id)
)

検証用のmainを作る

DaoのImplをルックアップしてきて、insertを呼び出している感じです。

fun main(args: Array<String>) {

    AppConfig.transactionManager.required {
        val user = User(null, "しおしお")
        val result = dao<UserDao>().insert(user)
        println("result.entity = ${result.entity}")
    }
}

実行!!

登録した結果、Entityの内容がUser{id=9, name='しおしお'}となっているのでいい感じに動きました。

4 18, 2017 8:47:12 午前 org.seasar.doma.jdbc.tx.LocalTransaction begin
情報: [DOMA2063] ローカルトランザクション[142666848]を開始しました。
4 18, 2017 8:47:12 午前 dao.UserDaoImpl insert
情報: [DOMA2220] ENTER  : クラス=[dao.UserDaoImpl], メソッド=[insert]
4 18, 2017 8:47:13 午前 dao.UserDaoImpl insert
情報: [DOMA2076] SQLログ : SQLファイル=[null],
insert into users (name) values ('しおしお')
4 18, 2017 8:47:13 午前 dao.UserDaoImpl insert
情報: [DOMA2221] EXIT   : クラス=[dao.UserDaoImpl], メソッド=[insert]
4 18, 2017 8:47:13 午前 org.seasar.doma.jdbc.tx.LocalTransaction commit
情報: [DOMA2067] ローカルトランザクション[142666848]をコミットしました。
result.entity = User{id=9, name='しおしお'}
4 18, 2017 8:47:13 午前 org.seasar.doma.jdbc.tx.LocalTransaction commit
情報: [DOMA2064] ローカルトランザクション[142666848]を終了しました。

テーブルをのぞいてみるとちゃんと登録されてます。

08:48:29 SQL> select * from users where id = 9;

        ID NAME
---------- ------------------------------
         9 しおしお

おわり。