光滑的插入,类型不匹配
Slick insert, type mismatch
我正在尝试使用 Slick 将一些数据插入到我的数据库中。我已经成功地查询了数据库,但不太明白如何使用文档示例插入数据。
我已经到了错误的地步,我的 action
类型不正确,它抛出了错误
type mismatch;
found : slick.dbio.DBIOAction[Unit,slick.dbio.NoStream,slick.dbio.Effect.Write with slick.dbio.Effect.Schema]
required: slick.dbio.DBIOAction[com.ojolabs.customer.avro.CustomerEvent,slick.dbio.NoStream,Nothing]
db.run(action)
我不太确定如何使用我已经编写的代码 return 根据需要指定的类型。
我从这里调用我的模式:
trait CustomerEventsComponent {
def customEventsManager: CustomerEvents.Async
}
trait DefaultCustomerEvents extends CustomerEventsComponent{
self: DatabaseComponent with ExecutionContextComponent =>
lazy val customEventsManager = new Async {
override def create(phoneNumber: String, createdAt: DateTime): Future[CustomerEvent] = {
val action = Schema.CustomerEvents.userAction
//this is the line that throws the error
db.run(action)
}
}
}
我正在这里创建动作
object Schema {
class CustomerEvents(tag: Tag) extends Table[CustomerEvent](tag, "customer_events") {
def id: Rep[UUID] = column[UUID]("id", O.PrimaryKey)
def customerId: Rep[UUID] = column[UUID]("customer_id")
def eventType: Rep[String] = column[String]("type")
def createdAt: Rep[DateTime] = column[DateTime]("created_at")
def version: Rep[Double] = column[Double]("version")
def data: Rep[JsValue] = column[JsValue]("data")
def metadata: Rep[JsValue] = column[JsValue]("metadata")
def * = (id, customerId, eventType, createdAt, version, data, metadata) <> (CustomerEvent.tupled, CustomerEvent.unapply)
}
object CustomerEvents {
val all = TableQuery[CustomerEvents]
val userAction = DBIO.seq(
all.schema.create,
all += CustomerEvent(
UUID.randomUUID(),
UUID.randomUUID(),
"hello",
DateTime.now(),
1.0,
Json.toJson("{\"hello\" : \"its me\"}"),
Json.toJson("{\"hello\" : \"its me\"}"))
)
}
为了让这个答案更短一些,我将引用 DBIO[T]
,它是 Slick 中 DBIOAction[T, NoStream, Effect.All]
[ 的别名=40=]
为什么会出现编译错误
错误是说编译器需要一个 DBIO[CustomerEvent]
但找到了一个 DBIO[Unit]
。它期望该类型,因为 create
被定义为 return a Future[CustomerEvent]
(因此 db.run
应该 return )。
但是,Schema.CustomerEvents.userAction
调用了 DBIO.seq
。 seq
是一种组合操作并忽略结果的方法。 DBIO.seq
的return类型是DBIO[Unit]
(参考:Scala Doc)。
这就是您看到错误的原因:代码正在使用一种会丢弃结果的方法组合操作。
怎么办
您可以为此做一些事情。
如果实在不想要插入的结果,把create
的类型改成Future[Unit]
如果您确实想要非 Unit
结果,则需要切换到与 seq
不同的 "combinator"。在这种情况下,我建议使用 andThen
,它结合了两个动作,并保留第二个动作的值。我稍后会解释...
插入的结果
+=
默认为 return 受影响的行数。如果这是您想要的,那将是 create
上的 Future[Int]
类型。
userAction
最终会变成:all.schema.create andThen (all += ...etc)
或者,如果您愿意,可以使用 for comprehension:
for {
_ <- all.schema.create
rowsAffected <- all += ...etc
} yield rowsAffected
(未使用 andThen
但结果相同)。
但是,如果您想要结果 class 的案例...好吧,您创建案例 class,这样您就可以 yield
它在上面的理解示例中. Slick 还支持 returning
和 into
作为更改 +=
表达式的 return 类型的一种方式:它在 the reference manual.
中有描述
我正在尝试使用 Slick 将一些数据插入到我的数据库中。我已经成功地查询了数据库,但不太明白如何使用文档示例插入数据。
我已经到了错误的地步,我的 action
类型不正确,它抛出了错误
type mismatch;
found : slick.dbio.DBIOAction[Unit,slick.dbio.NoStream,slick.dbio.Effect.Write with slick.dbio.Effect.Schema]
required: slick.dbio.DBIOAction[com.ojolabs.customer.avro.CustomerEvent,slick.dbio.NoStream,Nothing]
db.run(action)
我不太确定如何使用我已经编写的代码 return 根据需要指定的类型。
我从这里调用我的模式:
trait CustomerEventsComponent {
def customEventsManager: CustomerEvents.Async
}
trait DefaultCustomerEvents extends CustomerEventsComponent{
self: DatabaseComponent with ExecutionContextComponent =>
lazy val customEventsManager = new Async {
override def create(phoneNumber: String, createdAt: DateTime): Future[CustomerEvent] = {
val action = Schema.CustomerEvents.userAction
//this is the line that throws the error
db.run(action)
}
}
}
我正在这里创建动作
object Schema {
class CustomerEvents(tag: Tag) extends Table[CustomerEvent](tag, "customer_events") {
def id: Rep[UUID] = column[UUID]("id", O.PrimaryKey)
def customerId: Rep[UUID] = column[UUID]("customer_id")
def eventType: Rep[String] = column[String]("type")
def createdAt: Rep[DateTime] = column[DateTime]("created_at")
def version: Rep[Double] = column[Double]("version")
def data: Rep[JsValue] = column[JsValue]("data")
def metadata: Rep[JsValue] = column[JsValue]("metadata")
def * = (id, customerId, eventType, createdAt, version, data, metadata) <> (CustomerEvent.tupled, CustomerEvent.unapply)
}
object CustomerEvents {
val all = TableQuery[CustomerEvents]
val userAction = DBIO.seq(
all.schema.create,
all += CustomerEvent(
UUID.randomUUID(),
UUID.randomUUID(),
"hello",
DateTime.now(),
1.0,
Json.toJson("{\"hello\" : \"its me\"}"),
Json.toJson("{\"hello\" : \"its me\"}"))
)
}
为了让这个答案更短一些,我将引用 DBIO[T]
,它是 Slick 中 DBIOAction[T, NoStream, Effect.All]
[ 的别名=40=]
为什么会出现编译错误
错误是说编译器需要一个 DBIO[CustomerEvent]
但找到了一个 DBIO[Unit]
。它期望该类型,因为 create
被定义为 return a Future[CustomerEvent]
(因此 db.run
应该 return )。
但是,Schema.CustomerEvents.userAction
调用了 DBIO.seq
。 seq
是一种组合操作并忽略结果的方法。 DBIO.seq
的return类型是DBIO[Unit]
(参考:Scala Doc)。
这就是您看到错误的原因:代码正在使用一种会丢弃结果的方法组合操作。
怎么办
您可以为此做一些事情。
如果实在不想要插入的结果,把
create
的类型改成Future[Unit]
如果您确实想要非
Unit
结果,则需要切换到与seq
不同的 "combinator"。在这种情况下,我建议使用andThen
,它结合了两个动作,并保留第二个动作的值。我稍后会解释...
插入的结果
+=
默认为 return 受影响的行数。如果这是您想要的,那将是 create
上的 Future[Int]
类型。
userAction
最终会变成:all.schema.create andThen (all += ...etc)
或者,如果您愿意,可以使用 for comprehension:
for {
_ <- all.schema.create
rowsAffected <- all += ...etc
} yield rowsAffected
(未使用 andThen
但结果相同)。
但是,如果您想要结果 class 的案例...好吧,您创建案例 class,这样您就可以 yield
它在上面的理解示例中. Slick 还支持 returning
和 into
作为更改 +=
表达式的 return 类型的一种方式:它在 the reference manual.