在 ScalaQuery O/R 框架中映射自定义类型
Posted
技术标签:
【中文标题】在 ScalaQuery O/R 框架中映射自定义类型【英文标题】:Mapping custom types in the ScalaQuery O/R framework 【发布时间】:2012-06-21 10:19:49 【问题描述】:在他的comparison of ScalaQuery and Squeryl 中,Stefan Zeiger(ScalaQuery 的作者)在第三个要点中说:
ScalaQuery 支持一组基本的 JDBC 类型,并且可以 扩展了 DBMS 或特定于应用程序的类型。
但是,我一直无法找到有关如何实际执行此操作的示例或说明。我正在尝试为 Postgres 数据库编写 ScalaQuery 模式,其中一些列是我在 Postgres 中创建的自定义枚举类型。
例如,我有一个名为gender
的枚举类型,它的可能值有male
和female
。这不是 Java 枚举,以整数形式保存到数据库中。相反,它是在 DBMS 中定义的自定义 Postgres 类型。 Postgres 以特殊的 4 字节数据结构而不是原语存储那些。
如何将 gender
类型的 Postgres 列合并到 ScalaQuery 架构中?
(如果您认为不同的强类型 O/R 方法更适合该任务,我也会感谢 cmets。我已经看过 Squeryl,并且不相信它可以处理自定义类型,除非它们被持久化作为 DBMS 中的原语。)
【问题讨论】:
【参考方案1】:import org.scalaquery.ql.MappedTypeMapper => Mapper
object TypeMapper
type Stamp = java.sql.Timestamp
val joda2Stamp =
Mapper.base[JodaTime, Stamp](
dt => new Stamp(dt.getMillis),
ts => new JodaTime(ts.getTime) )
然后,例如,在您的 DAO(或您运行查询的任何地方)中,使用它:
import TypeMapper._
implicit val j2Stamp = joda2Stamp // type conversion automatically
您需要尝试为 Enums 和 PostGres 的枚举存储类型实现相同的目标。我倾向于不打扰,更喜欢使用 Java 枚举并存储为原始类型。
例如:
public enum CardType implements ILabel
V("Visa"),
M("MasterCard"),
D("Discover"),
A("American Express");
private CardType(String label) this.label = label;
public String getLabel() return this.label;
final String label;
public static List<String> asList()
return EnumHelper.asList(CardType.class);
public static Map<String,String> asMap()
return EnumHelper.asMap(CardType.class);
然后以 char(1) 形式存储在 DB 中,例如 Orders.insert(cardType = cardType.toString)
,或者您可以创建类型映射器 Enum-String 转换并在插入时省略 enum.toString...
【讨论】:
谢谢!我认为使用数据库原生枚举的开销比我想要处理的要多。我仍然希望在数据库级别强制执行枚举。但是,我想我会通过切换到 VARCHAR 类型来实现这一点......并在表上添加一个约束触发器,这将阻止 INSERT 和 UPDATE 的无效值。 是的,数据库枚举,不卖那个,你将如何创建一个 html 选择/收音机/复选框列表?您必须查询数据库。使用 Java 枚举,您可以在不查询数据库的情况下生成 html 元素(或者至少只查询包含您将获得的枚举值的目标记录),并且,如果您创建类型映射器枚举字符串,则可以强制执行DAO 持久化操作中的枚举值约束。当然,DB 触发器是最安全的,但是您必须在应用程序层处理一个异常,如果您始终首先通过 DAO 层持续存在,则该异常永远不会发生。有趣,有趣;-) 嗯,数据库原生枚举的好处是,当数据库在 Java 之外使用时,您仍然可以强制执行。我的大部分职业生涯都在为大公司工作,我只是习惯于假设数据库可能被 Java Web 应用程序、.NET 桌面应用程序、可能是一些 Perl 或 Python cron 作业等使用。所以我的直觉是远离依赖应用程序层在持久层中强制执行约束。我想如果您正在开发一个小型应用程序,而其他任何东西都不会写入数据库,那么您可以将更多责任放在应用程序的肩上。 哦,如果您确实使用数据库原生触发器,那么这些值仍然会在您的 JDBC 调用中以字符串(或您将它们转换为的任何内容)的形式出现。您无需进行任何花哨的翻译即可获得用户友好的值、填充 HTML 选择等。 顺便说一句...在我的第一条评论中,我的意思是“检查约束”而不是“约束触发器”。这种类型的强制执行可以嵌入到初始的“CREATE TABLE”语句中,无需添加单独的触发器。以上是关于在 ScalaQuery O/R 框架中映射自定义类型的主要内容,如果未能解决你的问题,请参考以下文章
Ninja 框架端点在尝试将 JSON 映射到自定义对象时抛出 500 错误