I would like to return the auto generated ID from an insert into a SQL Server table with an identity field
My first attempt, which returns a single row/column result set with the ID, was to use the @@IDENTITY functionality of SQL Server along with my insert statement.
i.e.)
val fooId = db.withSession((session: scala.slick.session.Session) => {
(sql"""
INSERT INTO Foo VALUES ('bar')
SELECT @@IDENTITY""").as[Int].first()(session)
})
However, in this case slick is always returning 1.
EDIT: I lied, it's always returning 1, which I think is the number of rows affected. As a test I tried modifying the query like so to see what would happen and I received an exception "java.lang.ClassCastException: java.lang.Integer cannot be cast to scala.Tuple2". It looks like it needs to return a scalar back in this case.
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)
})
EDIT 2: This works, but I think it makes two round trips. That probably means it could be victim to race conditions as well:
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: The more I think about this the more clear to me that given my usage of slick it's not really a slick topic, but more of a SQL Server and JDBC question. This is my latest solution.
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)
})
EDIT 4: This is the most concise solution. It makes use of the OUTPUT feature of SQL Server (thanks PB).
val fooId = db.withSession((session: scala.slick.session.Session) => {
(sql"""INSERT INTO Foo OUTPUT INSERTED.FooId VALUES ('bar')""").as[Int].first()(session)})