自定义数据类型的数据库映射方案

本文探讨了如何将自定义数据类型映射到数据库中,以适应复杂的数据结构需求。基础数据类型无法满足某些特定业务场景,例如身份证号码的存储。通过实现Hibernate的UserType、CompositeUserType等接口,可以将自定义类型映射成单列或多列。举例说明了MyString和MyChineseName的映射过程,展示了如何处理多字段组合的情况。此外,还提到了使用embedded特性将原本应为两个关联表的数据整合到一个表中,简化数据库结构。
摘要由CSDN通过智能技术生成

基础数据类型,如String、Integer、Date、Boolean等它们可以很方便的映射到数据库:

import grails.persistence.Entity

@Entity
class MyEntity {
    String code
    String name
    static constraints = {
        code(unique: true, minSize: 4, maxSize: 4)
        name(blank: false, maxSize: 255)
    }
}

这些基础数据类型是JAVA提供的语言级的,它没有语意。

比如要表达一个身份证号码:它有长度限制:15位或18位;还有规则限制;还能从身份证号码中提取出地址、性别、出生日期、年龄等信息。这些信息用一个String是无法表达,需要用类来描述:

class IDNumber{
    String idNumber

    Address address
    InsDate birthday
    Gender gender
    IDNumber() {}
    IDNumber(val) {       
        if (val.length() == 15) {
            val = to18IdNumber(val)
        }
        if (val.length() != 18) {
            throw new IllegalArgumentException("不是身份证格式")
        }
        this.idNumber = val
        return
    }
    def getAddress() {
        if (address) return address
        else return address = parseAddress()
    }
    def getBirthday() {
        if (birthday) return birthday
        else return birthday = parseBirth()
    }
    def getGender() {
        if (gender) return gender
        else return gender = parseGender()
    }
    def parseBirth() {
        ...
    }
}

这个类里面最核心的就是String idNumber身份证号码,其他属性都是暂存的临时数据,可以从身份证号码里解析出来。如果想把这个类映射到数据库中,现在只能映射成一个table,但映射成table又不合理,最好是能映射成一列:

@grails.persistence.Entity
class PersonInfo {
    String name
    IDNumber idNumber
}

现在这样显然是不能达到这个目标的。

Hibernate提供了多种实现自定义类型的方法:

1、实现org.hibernate.usertype.UserType

2、实现org.hibernate.usertype.CompositeUserType

3、实现org.hibernate.usertype.UserCollectionType

4、实现org.hibernate.usertype.EnhanceUserType

通过实现这些接口,可以将自定义数据类型映射成数据库列。

UserType可以映射成单列,CompositeUserType可以映射成多列。

看个例子:

class MyString extends InsDataType implements UserType{
    String value

    @Override
    void buildData(val) {
        if (val instanceof MyString) {
            value = val.value
            return
        }
        if (val == null) value = null
        else if (val instanceof String) value = val
        else if (val instanceof Number) value = String.valueOf(val)
        else value = val.toString()
        return
    }

    static MyString from(val) {
        if (val instanceof MyString) return val
        MyString data = new MyString()
        data.build(val)
        return data
    }

    public String toString() {
        return value
    }

    int[] sqlTypes() {
        return [Types.VARCHAR]
    }

    Class returnedClass() {
        return MyString
    }

    boolean equals(Object x, Object y) {
        MyString mx, my
        if (x instanceof String) mx = MyString.from(x)
        if (x instanceof MyString) mx = x

        if (y instanceof String) my = MyString.from(y)
        if (y instanceof MyString) my = y
        if (mx?.value == my?.value) return true
        return false
    }

    int hashCode(Object x) {
        return ((MyString) x)?.value?.hashCode()
    }

    Object nullSafeGet(ResultSet rs, String[] names, Object owner) {
        if (rs.wasNull()) return null
//        String stringFromDb = (String) Hibernate.STRING.nullSafeGet(rs, names[0]);
        String stringFromDb = rs.getString(names[0]);
        
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值