2015-07-31 2 views
3

Я пытаюсь получить Slick, выполнив небольшой тест. Я пытаюсь сделать вставку. Тест проходит, ошибок нет, но когда я проверяю db, запись не была вставлена.Slick 3 insert not inserting, но без ошибок

Что я делаю неправильно?

Вот мой тестовый код:

Примечания: Я инвалид первый «flatMap», потому что, когда я хотел проверить второй метод вставки, и что код не был выполнен, когда первая функция flatmap была включена.

Оба метода вставки не вставляют новую запись. Первый запрос для всех элементов работает. Строки «Test id: xx» печатаются на консоль.

object TestSlick extends App { 

    import slick.driver.PostgresDriver.api._ 
    import concurrent.ExecutionContext.Implicits.global 
    import concurrent.duration._ 

    val config = ConfigFactory.load() 
    val username = config.getString("app.database.jdbc.username") 
    val password = config.getString("app.database.jdbc.password") 
    val url: String = config.getString("app.database.jdbc.url") 

    val db = Database.forURL(url, username, password) 

    try { 
    import Tables._ 

    val res = db.run(headlines.result).map(_.foreach { 
     case HeadLineRow(id, _, _, _, _, companyId, text, from, days, end, user) => 
     println(s"Test id:$id") 
    }).flatMap { _ => 
//  println("Inserting....") 
//  val ts = Timestamp.valueOf(LocalDateTime.now()) 
//  val insertAction: DBIO[Option[Int]] = (headlines returning headlines.map(_.id)) += 
//  HeadLineRow(None, 100, 100, "tekst", ts, 5, ts, None, None, None, None) 
// 
//  db.run(insertAction.transactionally.map(
//  newId => println(s"New id: $newId")) 
//  ) 
// }.flatMap { _ => 
     println("Inserting....(2)") 
     val ts = Timestamp.valueOf(LocalDateTime.now()) 
     val insertAction = headlines.map(p => p) += HeadLineRow(None, 1921, 65, "tekst2", ts, 5, ts, None, None, None, None) 

     db.run(insertAction.transactionally.map(
     r => println(s"Insert result: ${r}")) 
    ) 
    } 

    Await.ready(res, 30 seconds); 

    } finally db.close() 
} 

И мой стол (генерируется с помощью генератора скользкий, а затем настроил немного (автоматическое вкл идентификатор, поменять местами некоторые свойства вокруг))

пакет com.wanneerwerkik.db.slick

// AUTO-GENERATED Slick data model 
/** Stand-alone Slick data model for immediate use */ 
object Tables extends { 
    val profile = slick.driver.PostgresDriver 
} with Tables 

/** Slick data model trait for extension, choice of backend or usage in the cake pattern. (Make sure to initialize this late.) */ 
trait Tables { 
    val profile: slick.driver.JdbcProfile 
    import profile.api._ 
    import slick.model.ForeignKeyAction 
    import slick.collection.heterogeneous._ 
    import slick.collection.heterogeneous.syntax._ 
    // NOTE: GetResult mappers for plain SQL are only generated for tables where Slick knows how to map the types of all columns. 
    import slick.jdbc.{GetResult => GR} 

    /** DDL for all tables. Call .create to execute. */ 
    lazy val schema = Array(headlines.schema).reduceLeft(_ ++ _) 
    @deprecated("Use .schema instead of .ddl", "3.0") 
    def ddl = schema 

    /** 
    * Entity class storing rows of table 'head_line_bar' 
    * @param id Database column id SqlType(int4), PrimaryKey 
    * @param createdBy Database column created_by SqlType(int4), Default(None) 
    * @param createdOn Database column created_on SqlType(timestamp), Default(None) 
    * @param updatedBy Database column updated_by SqlType(int4), Default(None) 
    * @param updatedOn Database column updated_on SqlType(timestamp), Default(None) 
    * @param companyId Database column company_id SqlType(int4), Default(None) 
    * @param contentType Database column content_type SqlType(varchar), Length(255,true), Default(None) 
    * @param fromDate Database column from_date SqlType(timestamp), Default(None) 
    * @param numberofdays Database column numberofdays SqlType(int4), Default(None) 
    * @param uptoEndDate Database column upto_end_date SqlType(timestamp), Default(None) 
    * @param userId Database column user_id SqlType(int4), Default(None) 
    */ 
    case class HeadLineRow(
     id: Option[Int], 
     userId: Int, 
     companyId: Int, 
     contentType: String, 
     fromDate: java.sql.Timestamp, 
     numberofdays: Int, 
     uptoEndDate: java.sql.Timestamp, 
     createdBy: Option[Int] = None, 
     createdOn: Option[java.sql.Timestamp] = None, 
     updatedBy: Option[Int] = None, 
     updatedOn: Option[java.sql.Timestamp] = None 
) 

    /** GetResult implicit for fetching HeadLineBarRow objects using plain SQL queries */ 
    implicit def GetResultHeadLineRow(implicit e0: GR[Int], e1: GR[Option[Int]], e2: GR[Option[java.sql.Timestamp]], e3: GR[Option[String]]): GR[HeadLineRow] = GR{ 
    prs => import prs._ 
    HeadLineRow.tupled((<<?[Int], <<[Int], <<[Int], <<[String], <<[java.sql.Timestamp], <<[Int], <<[java.sql.Timestamp], <<?[Int], <<?[java.sql.Timestamp], <<?[Int], <<?[java.sql.Timestamp])) 
    } 
    /** 
    * Table description of table head_line_bar. 
    * Objects of this class serve as prototypes for rows in queries. 
    */ 
    class Headlines(_tableTag: Tag) extends Table[HeadLineRow](_tableTag, "head_line_bar") { 
    def * = (id, userId, companyId, contentType, fromDate, numberofdays, uptoEndDate, createdBy, createdOn, updatedBy, updatedOn) <> (HeadLineRow.tupled, HeadLineRow.unapply) 
    /** Maps whole row to an option. Useful for outer joins. */ 
    def ? = (Rep.Some(id), userId, companyId, contentType, fromDate, numberofdays, uptoEndDate, createdBy, createdOn, updatedBy, updatedOn).shaped.<>({r=>import r._; _1.map(_=> HeadLineRow.tupled((_1.get, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11)))}, (_:Any) => throw new Exception("Inserting into ? projection not supported.")) 

    /** Database column id SqlType(int4), PrimaryKey */ 
    val id: Rep[Option[Int]] = column[Option[Int]]("id", O.PrimaryKey, O.AutoInc) 
    /** Database column user_id SqlType(int4), Default(None) */ 
    val userId: Rep[Int] = column[Int]("user_id") 
    /** Database column company_id SqlType(int4), Default(None) */ 
    val companyId: Rep[Int] = column[Int]("company_id") 
    /** Database column content_type SqlType(varchar), Length(255,true), Default(None) */ 
    val contentType: Rep[String] = column[String]("content_type", O.Length(255,varying=true)) 
    /** Database column from_date SqlType(timestamp), Default(None) */ 
    val fromDate: Rep[java.sql.Timestamp] = column[java.sql.Timestamp]("from_date") 
    /** Database column numberofdays SqlType(int4), Default(None) */ 
    val numberofdays: Rep[Int] = column[Int]("numberofdays") 
    /** Database column upto_end_date SqlType(timestamp), Default(None) */ 
    val uptoEndDate: Rep[java.sql.Timestamp] = column[java.sql.Timestamp]("upto_end_date") 
    /** Database column created_by SqlType(int4), Default(None) */ 
    val createdBy: Rep[Option[Int]] = column[Option[Int]]("created_by", O.Default(None)) 
    /** Database column created_on SqlType(timestamp), Default(None) */ 
    val createdOn: Rep[Option[java.sql.Timestamp]] = column[Option[java.sql.Timestamp]]("created_on", O.Default(None)) 
    /** Database column updated_by SqlType(int4), Default(None) */ 
    val updatedBy: Rep[Option[Int]] = column[Option[Int]]("updated_by", O.Default(None)) 
    /** Database column updated_on SqlType(timestamp), Default(None) */ 
    val updatedOn: Rep[Option[java.sql.Timestamp]] = column[Option[java.sql.Timestamp]]("updated_on", O.Default(None)) 
    } 
    /** Collection-like TableQuery object for table HeadLineBar */ 
    lazy val headlines = new TableQuery(tag => new Headlines(tag)) 

} 

Выход журнала слишком большой, чтобы вставить здесь, поэтому я положил его в this gist.

Как было предложено, я добавил readLine, чтобы дождаться результата, но он уже выдал те же самые вещи. Я также добавил обработчик завершения в будущее, чтобы напечатать его «Успех» или «Неудача». По-видимому, он не работает с RejectedExecutionException. Зачем?

Failure: java.util.concurrent.RejectedExecutionException: Task slick.backend.Dat[email protected] rejected from [email protected][Terminated, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 1] 
+0

Печатает ли что-нибудь вообще? В противном случае я подозреваю, что программа заканчивается более или менее немедленно. Попробуйте выполнить 'io.StdIn.readLine()' в качестве последней строки, требуя, чтобы приложение дождалось нажатия на ввод перед выходом. – Rikard

+0

Он уже печатал множество вещей. Я добавил «readLine», как было предложено, а также добавил обработчик завершения в Будущее, чтобы я мог видеть результат. Я добавил вывод к вопросу. По-видимому, будущее не работает с _RejectedExecutionException_. Зачем? –

+0

Похоже, что внутренний пул отключен (он говорит: [Закончено, пул = 0, активные потоки = 0, поставленные задачи = 0, завершенные задачи = 1]). Поэтому я предполагаю, что db.close() был вызван до того, как действие вставки может быть выполнено. Попробуйте поместить файл io.StdIn.readLine() сразу после Await.ready(). Возможно, также добавьте обработчики ошибок onFailure() 'на возникающие фьючерсы. – Rikard

ответ

0

Это только предположение, но, может быть, ваша система тестирования как-то смущает тот факт, что flatMap внутренне нерестится новую задачу, требуя снова контекст выполнения (смотри, например, this thread - это о Scala 2.10, но я думаю, что это не изменилось). Таким образом, ресурсы освобождаются до того, как ваша вставка будет выполнена.

Вы пытались помещать println в блок finally, чтобы узнать, вызвано ли это до или после сообщения, сопровождающего вставку?

Вы пытались запустить оба фьючерса синхронно, используя ожидание? Вероятно, вы не получите эту проблему в этом случае.

Вы можете рассмотреть возможность тестирования с полной асинхронной поддержкой, см., Например, this link.

+0

О, черт побери. Конечно, блок «finally» вызывается до того, как будущее завершится, так как результат Try - это будущее. И поэтому соединение было уже закрыто до того, как вставка могла иметь место. –