【问题标题】:Mapping custom types in the ScalaQuery O/R framework在 ScalaQuery O/R 框架中映射自定义类型
【发布时间】: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 中的原语。)

【问题讨论】:

    标签: postgresql scala orm scalaquery


    【解决方案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”语句中,无需添加单独的触发器。
    猜你喜欢
    • 1970-01-01
    • 2011-08-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-25
    • 2011-10-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多