Как вызывать хранимые процедуры и определенные функции в MySQL с помощью Slick 3.0

Я определил в своей БД что-то вроде этого

CREATE FUNCTION fun_totalInvestorsFor(issuer varchar(30)) RETURNS INT
NOT DETERMINISTIC
BEGIN
  RETURN (SELECT COUNT(DISTINCT LOYAL3_SHARED_HOLDER_ID) 
      FROM stocks_x_hldr
      WHERE STOCK_TICKER_SIMBOL = issuer AND
            QUANT_PURCHASES > QUANT_SALES);
END;

Теперь я получил ответ от Стефана Зейгера (руководитель Slick), который перенаправил меня сюда: Определяемые пользователем функции в Slick

Я пробовал (имея следующий объект):

lazy val db = Database.forURL("jdbc:mysql://localhost:3306/mydb",
driver = "com.mysql.jdbc.Driver", user = "dev", password = "root")
val totalInvestorsFor = SimpleFunction.unary[String, Int]("fun_totalInvestorsFor")
totalInvestorsFor("APPLE") should be (23)

Результат: Rep(slick.lifted.SimpleFunction$$anon$2@13fd2ccd fun_totalInvestorsFor, false) was not equal to 23

Я также пробовал, имея application.conf в src/main/resources следующим образом:

tsql = {
  driver = "slick.driver.MySQLDriver$"
  db {
    connectionPool = disabled
    driver = "com.mysql.jdbc.Driver"
    url = "jdbc:mysql://localhost/mydb"
  }
}

Затем в моем коде с @StaticDatabaseConfig("file:src/main/resources/application.conf#tsql")

tsql"select fun_totalInvestorsFor('APPLE')" should be (23)

Результат: Error:(24, 9) Cannot load @StaticDatabaseConfig("file:src/main/resources/application.conf#tsql"): No configuration setting found for key 'tsql' tsql"select fun_totalInvestorsFor('APPLE')" should be (23) ^

Я также планирую вызывать хранимые процедуры, которые возвращают один кортеж из трех значений, через sql"call myProc(v1).as[(Int, Int, Int)]

Любые идеи?

РЕДАКТИРОВАТЬ: при создании sql""""SELECT COUNT(DISTINCT LOYAL3_SHARED_HOLDER_ID) FROM stocks_x_hldr WHERE STOCK_TICKER_SIMBOL = issuer AND QUANT_PURCHASES > QUANT_SALES""".as[(Int)] приводит к SqlStreamingAction[Vector[Int], Int, Effect] вместо предложенного DBIO[Int] (из того, что я делаю вывод), предложенного документацией


person Tomas Duhourq    schedule 18.05.2015    source источник
comment
Попробуйте totalInvestorsFor("APPLE") should be LiteralColumn(23)   -  person pedrofurla    schedule 18.05.2015
comment
Это функция базы данных. Он должен пройти через базу данных внутри запроса для оценки. В противном случае это просто дерево выражений того, что должно происходить на стороне базы данных, а не результат.   -  person cvogt    schedule 18.05.2015
comment
ваш sql... должен быть DBIO[Vector[Int]]... как я думаю, потому что SqlStreamingAction является подтипом DBIOAction, который имеет псевдоним DBIO   -  person cvogt    schedule 18.05.2015
comment
Попробуйте вызвать на нем db.run и посмотрите, что получится.   -  person cvogt    schedule 18.05.2015
comment
Со следующей конфигурацией lazy val db = Database.forURL("jdbc:mysql://localhost:3306/mydb", driver = "slick.driver.MySQLDriver$", user = "root", password = "root") и вызывая ее с помощью `val f = db.run(dbio).value.get.get`, я получаю опцию None, подходят ли параметры db для MySQL?   -  person Tomas Duhourq    schedule 18.05.2015


Ответы (1)


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

Но я сопротивляюсь добавлению чистого JDBC или Anorm в наш стек решений, поэтому я нашел «приемлемое» исправление, ИМХО.

Решение состоит в том, чтобы получить объект сеанса от Slick, а затем использовать общий JDBC для управления вызовами хранимой функции/хранимой процедуры. В этот момент вы можете использовать любую стороннюю библиотеку, которая упрощает задачу... хотя в моем случае я написал свою собственную функцию для настройки вызова и возврата набора результатов.

val db = Database.forDataSource(DB.getDataSource)
var response: Option[GPInviteResponse] = None

db.withSession {
    implicit session => {
        // Set up your call here... (See my other post for a more detailed
        // answer with an example:
        // procedure is eg., "{?=call myfunction(?,?,?,?)}"
        val cs = session.conn.prepareCall(procedure.toString)
        // Set up your in and out parameters here
        // eg. cs.setLong(index, value)
        val result = cs.execute()
        val rc = result.head.asInstanceOf[Int]

        response = rc match {
            // Package up the response to the caller
        }
    }
}
db.close()

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

person Zac    schedule 18.05.2015
comment
Это намного, гораздо менее декларативно и менее FP, чем с предыдущей интерполяцией и наличием неявной сессии в области действия через предыдущие версии Slick, я думаю, что вернусь к этому. Спасибо, Зак! - person Tomas Duhourq; 19.05.2015