在 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 的枚举类型,它的可能值有malefemale。这不是 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 框架中映射自定义类型的主要内容,如果未能解决你的问题,请参考以下文章

从零打造在线网盘系统之Hibernate配置O/R映射

从实体框架映射到自定义域模型类?

如何将一个自定义实体映射到实体框架中的某些数据库表?

Ninja 框架端点在尝试将 JSON 映射到自定义对象时抛出 500 错误

实体框架 - 您能否将导入的存储过程的结果类型映射到自定义实体类型?

实体框架代码首先自定义字段,我不想映射到数据库