2011-02-26 54 views
8

我想爲我的域對象使用UUID作爲id。這個想法是,uuid可以由客戶端提供,如果沒有,則會生成UUID。我的定義,像這樣:使用uuid作爲id並映射到二進制列的grails

class Person { 
     static mapping = { 
     id generator:'assigned' 
     } 

     String id 

     def getUUID ={ 
      return java.util.UUID.randomUUID().toString(); 
     } 


      transient beforeInsert = { 
      if (id == null || id.equals("")) 
         id = getUUID(); 
      } 
} 

現在假設我剝包括在提供UUID java的UUID或客戶端中的破折號出來,我想這是存儲在一個二進制領域在我的MySQL數據庫。檢索時也有正確的格式發回。

我該如何做到這一點?思考一個更好的方法來做到這一點?

回答

3

Grails和hibernate通常會以字符串形式處理UUID。使用二進制UUID可能需要多一點工作。聲明id的類型爲UUID並提供一個hibernate用戶類型以將其序列化爲一個字節數組。您還需要告訴Grails用於UUID的SQL類型。例如:

class Person { 
    static mapping = { 
     id generator:'assigned', type: UUIDUserType, sqlType: 'varbinary(16)' 
    } 

    UUID id 

    def beforeInsert = { 
     if (!id) { 
      id = UUID.randomUUID() 
     } 
    } 
} 

爲UUID的用戶類型是:

import java.nio.ByteBuffer 
import java.nio.LongBuffer 
import java.sql.ResultSet 
import java.sql.PreparedStatement 
import java.sql.Types 
import org.hibernate.usertype.UserType 

public class UUIDUserType implements UserType { 

    int[] sqlTypes() { [Types.VARBINARY] as int [] } 
    Class returnedClass() { UUID } 

    Object nullSafeGet(ResultSet resultSet, String[] names, owner) { 
     byte[] value = resultSet.getBytes(names[0]) 
     return value ? bytesToUuid(value) : null 
    } 

    void nullSafeSet(PreparedStatement statement, value, int index) { 
     if (value == null) { 
       statement.setNull(index, Types.VARBINARY) 
     } else { 
       statement.setBytes(index, uuidToBytes(value)) 
     } 
    } 

    boolean equals(x, y) { x == y } 
    int hashCode(x) { x.hashCode() } 
    Object deepCopy(value) { value } 
    boolean isMutable() { false } 
    Serializable disassemble(value) { value } 
    Object assemble(Serializable cached, owner) { cached } 
    def replace(original, target, owner) { original } 

    static byte[] uuidToBytes(uuid) { 
     def bytes = new byte[16]; 
     ByteBuffer.wrap(bytes).asLongBuffer().with { 
      put(0, uuid.mostSignificantBits) 
      put(1, uuid.leastSignificantBits) 
     } 
     bytes 
    } 

    static UUID bytesToUuid(bytes) { 
     ByteBuffer.wrap(bytes).asLongBuffer().with { 
      new UUID(get(0), get(1)) 
     } 
    } 
} 
+0

這並不在MySQL工作:2011-02-27 10:18:33818 [主要] ERROR hbm2ddl.SchemaExport - 失敗:創建表人(id tinyblob非null,版本bigint不爲null,主鍵(id)) 2011-02-27 10:18:33,819 [main] ERROR hbm2ddl.SchemaExport - 在密鑰規範中使用的BLOB/TEXT列'id'密鑰長度 2011-02-27 10:18:36,702 [main] ERROR util.JDBCExceptionReporter - 表'testuuid.person'不存在 – imrank1 2011-02-27 15:20:35

+0

糟糕,你是對的。我假定grails自動處理非字符串UUID,但事實證明它不是。我已經用修正更新了答案。 – ataylor 2011-02-27 20:55:07

+0

ahh是一個自定義的usertype。我會認爲Grails或者Hibernate會爲我們處理這個問題。總的來說,解決方案工作..但是,當使用varbinary(16)作爲實體的主鍵時,grails/hibernate對於belongsTo關係有問題。唯一的解決方案似乎是首先手動創建數據庫方案。 – imrank1 2011-03-01 12:26:32