gpt4 book ai didi

scala - 在 Slick 中将两个可选列提取到一个案例类中

转载 作者:行者123 更新时间:2023-12-02 00:54:27 25 4
gpt4 key购买 nike

我在应用程序中有以下类型:

case class Widget(
id: Int,
name: String,
latlon: Option[Latlon],
)

case class Latlon(latitude: Double, longitude: Double)

我想将小部件存储在一个带有列的表中 id , name , latitudelongitude (最后两个是可选的)。我不在乎当只有一个 latlon 列是 NULL 而另一个不是时会发生什么。

(一些数据库有特殊的列类型来存储地理坐标。请忽略这个问题,因为类型已经简化。)

我试过像这样声明表:

  class Widgets(tag: Tag) extends Table[Widget](tag, Some(mySchema), "widgets") {
def id: Rep[Int] = column[Int]("id", O.PrimaryKey, O.AutoInc)
def name: Rep[String] = column[String]("name")
def latitude: Rep[Option[Double]] = column[Option[Double]]("latitude")
def longitude: Rep[Option[Double]] = column[Option[Double]]("longitude")

def toLatlon(value: (Option[Double], Option[Double])): Option[Latlon] =
Applicative[Option].map2(value._1, value._2)(Latlon.apply)

def fromLatlon(value: Option[Latlon]): Option[(Option[Double], Option[Double])] =
value.map(latlon => (Some(latlon.latitude), Some(latlon.longitude)))

def * =
(
id.?,
name,
alternateNames,
(latitude, longitude) <> (toLatlon, fromLatlon),
) <> (Widget.apply _ tupled, Widget.unapply)
}

这适用于获取数据,但在没有 latlon 的情况下插入数据时,出现错误:
java.util.NoSuchElementException: None.get
at scala.None$.get(Option.scala:366)
at scala.None$.get(Option.scala:364)
at slick.lifted.ShapedValue.$anonfun$$less$greater$1(Shape.scala:279)
at scala.Function1.$anonfun$andThen$1(Function1.scala:57)
at slick.relational.TypeMappingResultConverter.set(ResultConverter.scala:135)
at slick.relational.ProductResultConverter.set(ResultConverter.scala:68)
at slick.relational.ProductResultConverter.set(ResultConverter.scala:43)
at slick.relational.TypeMappingResultConverter.set(ResultConverter.scala:135)
at slick.jdbc.JdbcActionComponent$InsertActionComposerImpl$SingleInsertAction.$anonfun$run$15(JdbcActionComponent.scala:521)
at slick.jdbc.JdbcBackend$SessionDef.withPreparedInsertStatement(JdbcBackend.scala:432)
at slick.jdbc.JdbcBackend$SessionDef.withPreparedInsertStatement$(JdbcBackend.scala:429)
at slick.jdbc.JdbcBackend$BaseSession.withPreparedInsertStatement(JdbcBackend.scala:489)
at slick.jdbc.JdbcActionComponent$ReturningInsertActionComposerImpl.preparedInsert(JdbcActionComponent.scala:662)
at slick.jdbc.JdbcActionComponent$InsertActionComposerImpl$SingleInsertAction.run(JdbcActionComponent.scala:519)
at slick.jdbc.JdbcActionComponent$SimpleJdbcProfileAction.run(JdbcActionComponent.scala:30)
at slick.jdbc.JdbcActionComponent$SimpleJdbcProfileAction.run(JdbcActionComponent.scala:27)
at slick.basic.BasicBackend$DatabaseDef$$anon$3.liftedTree1$1(BasicBackend.scala:275)
at slick.basic.BasicBackend$DatabaseDef$$anon$3.run(BasicBackend.scala:275)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)

( Option 中的额外 fromLatlon 之所以存在是因为显然 <> 的类型需要它。)

我再次尝试使用 Slick documentation for custom case class mapping :

case class LiftedLatlon(latitude: Rep[Double], longitude: Rep[Double])

implicit object LatlonShape extends CaseClassShape(LiftedLatlon.tupled, Latlon.apply _ tupled)

def * =
(
id.?,
name,
alternateNames,
LiftedLatlon(latitude, longitude),
) <> (Widget.apply _ tupled, Widget.unapply)

这似乎适用于所需的列,但它的类型是 latitude , longitude<> 的第一个参数不匹配,因为在 Widget类(class), latlon是可选的。

如何将我拥有的两个可选字段组合为一个,并且能够在没有可选部分的情况下插入整个值?

为什么 <> 的论证存在不对称性( f: (U => R), g: (R => Option[U] )?

最佳答案

看来 <> 的最后一个参数需要返回 Some .我没有从文档中得到确认,但这对应于使用 (apply, unapply) 对的典型用例,如 unapply允许失败。 <>的实现显式解包预期的 Some ( Shape.scala:279 ) 使用它的参数 gg.andThen(_.get) .

因此,要修复原来的问题fromLatlon必须改写为:

def fromLatlon(value: Option[Latlon]): Option[(Option[Double], Option[Double])] = 
Some(
(value.map(_.latitude), value.map(_.longitude))
)

关于scala - 在 Slick 中将两个可选列提取到一个案例类中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55507260/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com