INSERTクエリ
概要
INSERTクエリはQueryDsl
のinsert
とそれに続く関数を呼び出して構築します。
クエリ実行時にキーが重複した場合、org.komapper.core.UniqueConstraintException
がスローされます。
single
エンティティ1件を追加するにはsingle
を呼び出します。
val address: Address = Address(16, "STREET 16", 0)
val query: Query<Address> = QueryDsl.insert(a).single(address)
/*
insert into ADDRESS (ADDRESS_ID, STREET, VERSION) values (?, ?, ?)
*/
このクエリを実行した場合の戻り値は追加されたデータを表す新しいエンティティです。
下記のマッピング定義に応じて、発行されるSQLにも新しいエンティティにも適切な値が反映されます。
@KomapperAutoIncrement
@KomapperSequence
@KomapperVersion
@KomapperCreatedAt
@KomapperUpdatedAt
multiple
1文でエンティティ複数件を追加するにはmultiple
を呼び出します。
val query: Query<List<Address>> = QueryDsl.insert(a).multiple(
Address(16, "STREET 16", 0),
Address(17, "STREET 17", 0),
Address(18, "STREET 18", 0)
)
/*
insert into ADDRESS (ADDRESS_ID, STREET, VERSION) values (?, ?, ?), (?, ?, ?), (?, ?, ?)
*/
このクエリを実行した場合の戻り値は追加されたデータを表す新しいエンティティのリストです。
下記のマッピング定義に応じて、発行されるSQLにも新しいエンティティにも適切な値が反映されます。
@KomapperAutoIncrement
@KomapperSequence
@KomapperVersion
@KomapperCreatedAt
@KomapperUpdatedAt
batch
バッチでエンティティ複数件を追加するにはbatch
を呼び出します。
val query: Query<List<Address>> = QueryDsl.insert(a).batch(
Address(16, "STREET 16", 0),
Address(17, "STREET 17", 0),
Address(18, "STREET 18", 0)
)
/*
insert into ADDRESS (ADDRESS_ID, STREET, VERSION) values (?, ?, ?)
insert into ADDRESS (ADDRESS_ID, STREET, VERSION) values (?, ?, ?)
insert into ADDRESS (ADDRESS_ID, STREET, VERSION) values (?, ?, ?)
*/
このクエリを実行した場合の戻り値は追加されたデータを表す新しいエンティティのリストです。
下記のマッピング定義に応じて、発行されるSQLにも新しいエンティティにも適切な値が反映されます。
@KomapperAutoIncrement
@KomapperSequence
@KomapperVersion
@KomapperCreatedAt
@KomapperUpdatedAt
onDuplicateKeyIgnore
onDuplicateKeyIgnore
を呼び出すことでキーが重複した場合のエラーを無視できます。
onDuplicateKeyIgnore
には重複チェック対象のキーを指定できます。指定されない場合は主キーが使われます。
val address: Address = ..
val query: Query<Address?> = QueryDsl.insert(a).onDuplicateKeyIgnore().executeAndGet(address)
上記クエリに対応するSQLはどのDialectを使うかで異なります。 例えば、MariaDBのDialectを使う場合は次のようなSQLになります。
insert ignore into ADDRESS (ADDRESS_ID, STREET, VERSION) values (?, ?, ?)
PostgreSQLのDialectを使う場合は次のようなSQLになります。
insert into ADDRESS as t0_ (ADDRESS_ID, STREET, VERSION) values (?, ?, ?) on conflict (ADDRESS_ID) do nothing
Warning
auto increment カラムは重複しません。executeAndGet
onDuplicateKeyIgnore
に続けてexecuteAndGet
を呼び出した場合、戻り値は追加されたデータを表すエンティティです。
キーが重複していた場合はnull
が戻ります。
single
onDuplicateKeyIgnore
に続けてsingle
を呼び出した場合の戻り値はドライバの返す値です。
multiple
onDuplicateKeyIgnore
に続けてmultiple
を呼び出した場合の戻り値はドライバの返す値です。
batch
onDuplicateKeyIgnore
に続けてbatch
を呼び出した場合の戻り値はドライバの返す値です。
onDuplicateKeyUpdate
onDuplicateKeyUpdate
を呼び出すことでキーが重複した場合に対象行を更新できます。
onDuplicateKeyUpdate
には重複チェック対象のキーを指定できます。指定されない場合は主キーが使われます。
val department: Department = ..
val query: Query<Address> = QueryDsl.insert(d).onDuplicateKeyUpdate().executeAndGet(department)
上記クエリに対応するSQLはどのDialectを使うかで異なります。 例えば、MariaDBのDialectを使う場合は次のようなSQLになります。
insert into DEPARTMENT (DEPARTMENT_ID, DEPARTMENT_NO, DEPARTMENT_NAME, LOCATION, VERSION) values (?, ?, ?, ?, ?) on duplicate key update DEPARTMENT_NO = values(DEPARTMENT_NO), DEPARTMENT_NAME = values(DEPARTMENT_NAME), LOCATION = values(LOCATION), VERSION = values(VERSION)
PostgreSQLのDialectを使う場合は次のようなSQLになります。
insert into DEPARTMENT as t0_ (DEPARTMENT_ID, DEPARTMENT_NO, DEPARTMENT_NAME, LOCATION, VERSION) values (?, ?, ?, ?, ?) on conflict (DEPARTMENT_ID) do update set DEPARTMENT_NO = excluded.DEPARTMENT_NO, DEPARTMENT_NAME = excluded.DEPARTMENT_NAME, LOCATION = excluded.LOCATION, VERSION = excluded.VERSION
Warning
更新される行に楽観的ロックは適用されません。Warning
auto increment カラムは重複しません。executeAndGet
onDuplicateKeyUpdate
に続けてexecuteAndGet
を呼び出した場合、戻り値は追加もしくは更新されたデータを表すエンティティです。
single
onDuplicateKeyUpdate
に続けてsingle
を呼び出した場合の戻り値はドライバの返す値です。
multiple
onDuplicateKeyUpdate
に続けてmultiple
を呼び出した場合の戻り値はドライバの返す値です。
batch
onDuplicateKeyUpdate
に続けてbatch
を呼び出した場合の戻り値はドライバの返す値です。
set
onDuplicateKeyUpdate
の呼び出し後、set
を使って更新対象のカラムに特定の値を設定できます。
val department: Department = ..
val query = QueryDsl.insert(d).onDuplicateKeyUpdate().set { excluded ->
d.departmentName eq "PLANNING2"
d.location eq concat(d.location, concat("_", excluded.location))
}.single(department)
set
関数に渡すラムダ式にはexcluded
パラメータがあります。
excluded
は、追加しようとしているエンティティのメタモデルを表します。
したがって、excluded
の利用により追加しようとしているデータに基づいた更新を実現できます。
PostgreSQLのDialectを使う場合、上記のクエリは次のようなSQLとして発行されます。
insert into DEPARTMENT as t0_ (DEPARTMENT_ID, DEPARTMENT_NO, DEPARTMENT_NAME, LOCATION, VERSION) values (?, ?, ?, ?, ?) on conflict (DEPARTMENT_ID) do update set DEPARTMENT_NAME = ?, LOCATION = (concat(t0_.LOCATION, (concat(?, excluded.LOCATION))))
MySQLのDialectを使う場合、上記のクエリは次のようなSQLとして発行されます。
insert into DEPARTMENT (DEPARTMENT_ID, DEPARTMENT_NO, DEPARTMENT_NAME, LOCATION, VERSION) values (?, ?, ?, ?, ?) as excluded on duplicate key update DEPARTMENT_NAME = ?, LOCATION = (concat(DEPARTMENT.LOCATION, (concat(?, excluded.LOCATION))))
where
onDuplicateKeyUpdate
の呼び出し後、where
を使って更新条件を設定できます。
val department: Department = ..
val query = QueryDsl.insert(d).onDuplicateKeyUpdate().where {
d.departmentName eq "PLANNING"
}.single(department)
Warning
MariaDBやMySQLのDialectではサポートされていません。dangerouslyOnDuplicateKeyIgnore
この関数は、任意のconflict_targetを指定できることを除いて、onDuplicateKeyIgnoreと同等です。
Warning
この関数にSQLインジェクションの可能性がある文字列を渡さないでください。Warning
PostgreSQLのDialectでのみサポートされます。 conflict_targetについてはPostgreSQLのドキュメントを参照ください。 https://www.postgresql.org/docs/current/sql-insert.htmldangerouslyOnDuplicateKeyUpdate
この関数は、任意のconflict_targetを指定できることを除いて、onDuplicateKeyUpdateと同等です。
Warning
この関数にSQLインジェクションの可能性がある文字列を渡さないでください。Warning
PostgreSQLのDialectでのみサポートされます。 conflict_targetについてはPostgreSQLのドキュメントを参照ください。 https://www.postgresql.org/docs/current/sql-insert.htmlvalues
プロパティごとの値を設定して1件を追加するにはvalues
関数にラムダ式を渡します。
ラムダ式の中ではeq
関数を使って値を設定できます。
val query: Query<Pair<Long, Int?>> = QueryDsl.insert(a).values {
a.addressId eq 19
a.street eq "STREET 16"
a.version eq 0
}
/*
insert into ADDRESS (ADDRESS_ID, STREET, VERSION) values (?, ?, ?)
*/
eqIfNotNull
を使って値がnull
でない場合にのみ値を設定することもできます。
val query: Query<Pair<Long, Int?>> = QueryDsl.insert(a).values {
a.addressId eq 19
a.street eqIfNotNull street
a.version eq 0
}
クエリを実行した場合の戻り値は追加された件数と生成されたIDのPair
です。
IDはマッピング定義に@KomapperAutoIncrement
や@KomapperSequence
が注釈されている場合にのみ返されます。
以下のマッピング定義を持つプロパティについて明示的にeq
を呼び出さない場合、発行されるSQLに自動で値が設定されます。
明示的にeq
を呼び出した場合は明示した値が優先されます。
@KomapperSequence
@KomapperVersion
@KomapperCreatedAt
@KomapperUpdatedAt
@KomapperAutoIncrement
の定義は常に有効です。明示的に値をeq
した場合、無視されます。
select
検索結果を追加するにはselect
を呼び出します。
val aa = Meta.address.clone(table = "ADDRESS_ARCHIVE")
val query: Query<Long, List<Int>> = QueryDsl.insert(aa).select {
QueryDsl.from(a).where { a.addressId between 1..5 }
}
/*
insert into ADDRESS_ARCHIVE (ADDRESS_ID, STREET, VERSION) select t1_.ADDRESS_ID, t1_.STREET, t1_.VERSION from ADDRESS as t1_ where t1_.ADDRESS_ID between ? and ?
*/
クエリを実行した場合の戻り値は追加された件数と生成されるIDのリストのPair
です。
IDはエンティティクラスのマッピング定義に@KomapperAutoIncrement
が注釈されている場合にのみ生成されます。
以下のマッピング定義は考慮されません。
@KomapperSequence
@KomapperVersion
@KomapperCreatedAt
@KomapperUpdatedAt
returning
以下の関数の後続でreturning
関数を呼び出すことで、 追加された値や更新された値を取得できます。
- single
- multiple
- values
single
関数の後続でreturning
関数を呼び出す例です。
val address: Address = Address(16, "STREET 16", 0)
val query: Query<Address> = QueryDsl.insert(a).single(address).returning()
/*
insert into ADDRESS (ADDRESS_ID, STREET, VERSION) values (?, ?, ?) returning ADDRESS_ID, STREET, VERSION
*/
returning
関数にプロパティを指定することで取得対象のカラムを限定できます。
val query: Query<Int?> = QueryDsl.insert(a).single(address).returning(a.addressId)
/*
insert into ADDRESS (ADDRESS_ID, STREET, VERSION) values (?, ?, ?) returning ADDRESS_ID
*/
val query: Query<Pair<Int?, String?>> = QueryDsl.insert(a).single(address).returning(a.addressId, a.street)
/*
insert into ADDRESS (ADDRESS_ID, STREET, VERSION) values (?, ?, ?) returning ADDRESS_ID, STREET
*/
val query: Query<Triple<Int?, String?, Int?>> = QueryDsl.insert(a).single(address).returning(a.addressId, a.street, a.version)
/*
insert into ADDRESS (ADDRESS_ID, STREET, VERSION) values (?, ?, ?) returning ADDRESS_ID, STREET, VERSION
*/
returning
関数は、onDuplicateKeyIgnore
関数やonDuplicateKeyUpdate
関数と組み合わせて使用することもできます。
val departments = listOf(
Department(5, 50, "PLANNING", 1),
Department(1, 60, "DEVELOPMENT", 1),
)
val query: Query<List<Department>> = QueryDsl.insert(d).onDuplicateKeyUpdate().multiple(departments).returning()
/*
insert into department as t0_ (department_id, department_no, department_name, version)
values (?, ?, ?, ?), (?, ?, ?, ?) on conflict (department_id)
do update set department_no = excluded.department_no, department_name = excluded.department_name, version = excluded.version
returning department_id, department_no, department_name, version
*/
Warning
returning
関数は次のDialectでのみサポートされています。
- H2
- MariaDB
- Oracle Database
- PostgreSQL
- SQL Server
ただし、Oracle DatabaseのDialectでreturning
関数を使う場合、次のような制限があります。
- R2DBCはサポートされない
multiple
関数との組み合わせはサポートされないonDuplicateKeyIgnore
関数やonDuplicateKeyUpdate
関数との組み合わせはサポートされない
options
クエリの挙動をカスタマイズするにはoptions
を呼び出します。
ラムダ式のパラメータはデフォルトのオプションを表します。
変更したいプロパティを指定してcopy
メソッドを呼び出してください。
val address: Address = Address(16, "STREET 16", 0)
val query: Query<Address> = QueryDsl.insert(a).single(address).options {
it.copy(
queryTimeoutSeconds = 5
)
}
指定可能なオプションには以下のものがあります。
- batchSize
- バッチサイズです。デフォルトは
null
です。 - disableSequenceAssignment
- IDにシーケンスで生成した値をアサインすることを無効化するかどうかです。デフォルトは
false
です。 - queryTimeoutSeconds
- クエリタイムアウトの秒数です。デフォルトは
null
でドライバの値を使うことを示します。 - returnGeneratedKeys
- AUTO INCREMENTされたIDの値を返すかどうかです。デフォルトは
true
です。 - suppressLogging
- SQLのログ出力を抑制するかどうかです。デフォルトは
false
です。
executionOptions の同名プロパティよりもこちらに明示的に設定した値が優先的に利用されます。