2010-11-24 80 views
8

我正在遷移舊系統以使用Hibernate 3.它當前會生成自己的標識符。爲了保持系統當前的功能,然後嘗試將其移到更好的位置,我將如何指定(使用註釋)我自己的類,以便在插入時返回自定義生成的標識符?將自定義標識符分配給@id屬性

是這樣的:

@Id 
@CustomIdGenerator(Foo.class) // obviously this is not a real annotation 
public String getId() { ... } 

Foo類具有生成所述標識符的一種方法。

目前我只是手動調用setId(String id)方法,但希望有一個更好的方法來處理這種情況。

回答

7

我不認爲這是用於使用定製標註使用純JPA的2 API定製標識出的現成的支持。但是如果你想使用提供商特定的API,那麼這項工作非常簡單。 Sample Example

要獨立提供者嘗試以下任何技巧....

IdGeneratorHolder

public abstract class IdGeneratorHolder { 
    /* PersistentEntity is a marker interface */ 
    public static IdGenerator getIdGenerator(Class<? extends PersistentEntity> entityType) { 
      /* sample impelementation */ 
     if(Product.class.isAssignableFrom(entityType)) { 
      return new ProductIdGenerator(); 

     } 
     return null; 
    } 
} 

一般IdGenerator接口

public interface IdGenerator { 
    String generate(); 
} 

具體IdGenerator - 產品ID生成

public class ProductIdGenerator implements IdGenerator { 
    public String generate() { 
      /* some complicated logic goes here */ 
     return ${generatedId}; 
    } 
} 

現在將生成的ID或者設置爲無參數構造函數,使用@PrePersist方法

Product.java

public class Product implements PersistentEntity { 

    private String id; 

    public Product() { 
     id = IdGeneratorHolder.getIdGenerator(getClass()).generate(); 
    } 

    @PrePersist 
    public void generateId() { 
     id = IdGeneratorHolder.getIdGenerator(getClass()).generate(); 
    } 

} 

在上面的例子中所有的ID具有相同的類型,即java.lang.String的。如果持久實體有不同類型的IDS .....

IdGenerator.java

public interface IdGenerator { 
    CustomId generate(); 
} 

CustomId.java

public class CustomId { 

    private Object id; 

    public CustomId(Object id) { 
     this.id = id; 
    } 

    public String toString() { 
     return id.toString(); 
    } 
    public Long toLong() { 
     return Long.valueOf(id.toString()); 
    } 
} 

Item.java

@PrePersist 
    public void generateId() { 
     id = IdGeneratorHolder.getIdGenerator(getClass()).generate().toLong(); 
    } 

您還可以使用自定義的註釋......

CustomIdGenerator.java

public @interface CustomIdGenerator { 
    IdStrategy strategy(); 
} 

IdStrategy.java

enum IdStrategy { 
     uuid, humanReadable,  
    } 

IdGeneratorHolder.java

public abstract class IdGeneratorHolder { 
    public static IdGenerator getIdGenerator(Class<? extends PersistentEntity> entityType) { 
     try { // again sample implementation 
      Method method = entityType.getMethod("idMethod"); 
      CustomIdGenerator gen = method.getAnnotation(CustomIdGenerator.class); 
      IdStrategy strategy = gen.strategy(); 
      return new ProductIdGenerator(strategy); 
     } 

還有一件事......如果我們在@PrePersist方法中設置了id,則equals()方法不能依賴id字段(即,代理鍵),我們必須使用業務/自然鍵來實現equals()方法。但是,如果我們在無參數構造函數中將id字段設置爲某個唯一值(uuid或應用程序中唯一的「app-uid」),它可以幫助我們實現equals()方法。

public boolean equals(Object obj) { 
     if(obj instanceof Product) { 
      Product that = (Product) obj; 
      return this.id ==that.id; 
     } 
     return false; 
    } 

如果我們或他人通話(有意或錯誤)的@PrePersist註解的方法1倍以上,「唯一的ID將被改變!」所以在no-arg構造函數中設置id是可取的。或者爲了解決這個問題,把一個非空檢查...

@PrePersist 
    public void generateId() { 
     if(id != null) 
      id = IdGeneratorHolder.getIdGenerator(getClass()).generate(); 
    } 
} 

UPDATE

如果我們把ID生成的 無參數的構造函數,那不是 從數據庫加載實體 時產生問題?因爲Hibernate 將調用無參數的構造 導致現有的IDS是 重新生成

是的,你說得對,我錯過了一部分。 :(其實,我想告訴你的是: - 在我的應用程序中每個實體對象與組織實體相關聯的,所以我創建了一個抽象的超類有兩個構造函數,每一個實體(組織除外)擴展該類

protected PersistentEntityImpl() { 
    } 

    protected PersistentEntityImpl(Organization organization) { 
     String entityId = UUIDGenerator.generate(); 
     String organizationId = organization.getEntityId(); 
     identifier = new EntityIdentifier(entityId, organizationId); 
    } 

的無參數的構造是JPA的供應商,我們從來沒有調用無參數的構造函數,但其​​他組織根據構造函數。正如你所看到的,ID是在基礎的組織構造函數分配的。(我真的錯過了這一點同時寫出答案,對不起)

看看你是否可以在你的應用中實現這個或者類似的策略

第二個選項是使用 @PrePersist批註。我把在 和方法不會被擊中,並給了我 的異常,說明我需要 手動設置的ID。是否有 我應該做的其他事情?

理想情況下,在保持實體對象之前,JPA提供者應該調用@PrePersist方法(在類中聲明的方法以及在超類中聲明的所有其他方法)。不能告訴你什麼是錯的,除非你顯示一些代碼和控制檯。

1

您可以。

一是落實org.hibernate.id.IdentifierGenerator

然後,你必須將它在映射xml文件映射。我不能找到一種方法用註解做到這一點:

<!-- 
    <identifier-generator.../> allows customized short-naming 
     of IdentifierGenerator implementations. 
--> 
<!ELEMENT identifier-generator EMPTY> 
    <!ATTLIST identifier-generator name CDATA #REQUIRED> 
    <!ATTLIST identifier-generator class CDATA #REQUIRED> 

最後,使用@GeneratedValue(generator="identifier-name")

注意,這是休眠特定的(不是JPA)

更新:我花了看看Hibernate的來源,看起來在一個地方,在解決短名稱失敗後,休眠嘗試呼叫Class.forName(..)。那裏的參數叫做strategy。因此,這裏是你嘗試什麼:

  • 嘗試在generator屬性
  • 嘗試在@GenericGeneratorstrategy屬性設置類FQN爲字符串(有一些任意名稱)
設置類完全合格的名稱作爲字符串

讓我知道(如果有的話)的工作

+0

我看過一樣,如果可能的話,想避免xml文件。但是如果我找不到替代品,我想我會訴諸於此。謝謝! – digiarnie 2010-11-24 01:47:09

+0

@digiarnie看到更新 – Bozho 2010-11-24 07:27:00

相關問題