ID フィールドを持つ SQL Server テーブルへの挿入から自動生成された ID を返したい
ID を含む単一の行/列の結果セットを返す最初の試みは、insert ステートメントと共に SQL Server の @@IDENTITY 機能を使用することでした。
すなわち)
val fooId = db.withSession((session: scala.slick.session.Session) => {
(sql"""
INSERT INTO Foo VALUES ('bar')
SELECT @@IDENTITY""").as[Int].first()(session)
})
ただし、この場合、slick は常に 1 を返します。
編集:嘘をつきました。常に1を返します。これは、影響を受ける行の数だと思います。テストとして、クエリをそのように変更して何が起こるかを確認しようとしたところ、「java.lang.ClassCastException: java.lang.Integer を scala.Tuple2 にキャストできません」という例外が発生しました。この場合、スカラーを返す必要があるようです。
val fooIdTuple = db.withSession((session: scala.slick.session.Session) => {
(sql"""
INSERT INTO Foo VALUES ('bar')
SELECT @@IDENTITY as Foo, 47 as Bar""").as[(Int, Int)].first()(session)
})
編集2:これは機能しますが、2回の往復になると思います。これはおそらく、競合状態の犠牲になる可能性があることを意味します。
val fooId = db.withSession((session: scala.slick.session.Session) => {
(sql"""INSERT INTO Foo VALUES ('bar')""").as[Int].first()(session)
(sql"""SELECT @@IDENTITY""").as[Int].first()(session)
})
EDIT 3:これについて考えれば考えるほど、私のスリックの使用法を考えると、それは実際にはスリックなトピックではなく、SQL ServerとJDBCの質問であることがより明確になります。これが私の最新のソリューションです。
val fooId = db.withSession((session: scala.slick.session.Session) => {
(sql"""
SET NOCOUNT ON
INSERT INTO Foo VALUES ('bar')
SET NOCOUNT OFF
SELECT @@IDENTITY""").as[Int].first()(session)
})
編集 4: これは最も簡潔な解決策です。SQL ServerのOUTPUT 機能を利用します (PB さんに感謝)。
val fooId = db.withSession((session: scala.slick.session.Session) => {
(sql"""INSERT INTO Foo OUTPUT INSERTED.FooId VALUES ('bar')""").as[Int].first()(session)})