给出:
case class Money(value: BigDecimal, currency: Currency)
trait Currency
case class EUR ( ... ) extends Currency
... and so on
我想对一个可选的Money
类型进行建模,该类型包含一个value
部分(BigDecimal)和一个Currency
部分(一个Enum到Enumeratum)。
要在数据库中映射它,我有两个可选的列:
private def moneyOptionalValue: Rep[Option[BigDecimal]] = column[Option[BigDecimal]]("money_value")
private def moneyOptionalCurrency: Rep[Option[Currency]] = column[Option[Currency]]("money_currency")
所需状态是:
def money: Rep[Option[Money]] = ...
我尝试了这种方法,如 http://slick.lightbend.com/doc/3.1.0/userdefined.html#using-custom-record-types-in-queries
private implicit def myCurrencyType: BaseColumnType[Currency] = MappedColumnType.base[Currency, String](
c => c.shortName,
s => Currency.withNameUppercaseOnly(s.toUpperCase)
)
case class LiftedMoney(value: Rep[BigDecimal], currency: Rep[Currency])
case class LiftedMoneyOptional(a: Rep[Option[BigDecimal]], b: Rep[Option[Currency]])
case class MoneyOptional(a: Option[BigDecimal], b: Option[Currency])
// custom case class mapping
implicit object MoneyOptionalShape extends CaseClassShape(LiftedMoneyOptional.tupled, MoneyOptional.tupled)
implicit object MoneyShape extends CaseClassShape(LiftedMoney.tupled, Money.tupled)
implicit object MoneyToOptional
extends Isomorphism[Option[Money], MoneyOptional](
{
case Some(m) => MoneyOptional(Some(m.value), Some(m.currency))
case None => MoneyOptional(None, None)
}, {
case MoneyOptional(Some(v), Some(c)) => Some(Money(v, c))
case MoneyOptional(_, _) => None
}
)
private def moneyOptionalValue: Rep[Option[BigDecimal]] = column[Option[BigDecimal]]("money_value")
private def moneyOptionalCurrency: Rep[Option[Currency]] = column[Option[Currency]]("money_currency")
def moneyOptional: Rep[MoneyOptional] =
moneyOptionalValue.zip(moneyOptionalCurrency).mapTo[MoneyOptional]
def moneyOptional1: MappedProjection[MoneyOptional, (Option[BigDecimal], Option[Currency])] =
moneyOptionalValue.zip(moneyOptionalCurrency).mapTo[MoneyOptional]
// this compiles, if its not optional, but would break at runtime, when null values are in the columns:
private def moneyValue: Rep[BigDecimal] = column[BigDecimal]("money_value") // this column can be nullable!
private def moneyCurrency: Rep[Currency] = column[Currency]("money_currency") // // this column can be nullable!
def money: Rep[Money] = moneyValue.zip(moneyCurrency).value.mapTo[Money]
// I also tried this, but cannot compile my code with that for some reason
def optionMoney: Rep[Option[Money]] = RepOption[Money](money, money.toNode)
任何帮助将不胜感激!
答案 0 :(得分:0)
那一个呢?
def money = (moneyOptionalValue, moneyOptionalCurrency) <> [Option[Money]](
{
case (value,currency) if value.isDefined && currency.isDefined => Some(Money(value.get, currency.get))
case _ => None
},
(mapped:Option[Money]) => mapped.map( m => Some(Some(m.value), Some(m.currency))).getOrElse(Some(None,None))
)