2010-12-02 15 views
7

के साथ मैपिंग सरणी क्या आप कृपया मुझे कक्षा कक्षा Hbernate मानचित्र बनाने में मदद कर सकते हैं?हाइबरनेट

public class MyClass{ 
    private Long id; 
    private String name; 
    private int[] values; 
    ... 
} 

मैं PostgreSQL और स्तंभ प्रकार n तालिका का उपयोग कर रहा पूर्णांक [] कैसे मेरी सरणी मैप किया जाना चाहिए है?

उत्तर

6

मैंने कभी भी हाइबरनेट करने के लिए सरणी मैप नहीं किए हैं। मैं हमेशा संग्रह का उपयोग करता हूं।

public class MyClass{ 
    private Long id; 
    private String name; 
    private List<Integer> values; 

    @Id 
    // this is only if your id is really auto generated 
    @GeneratedValue(strategy=GenerationType.AUTO) 
    public Long getId() { 
     return id; 
    } 

    @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY) 
    public List<Integer> getValues() { 
     return values; 
    } 
    ... 
+3

यह काम नहीं करता। 'के कारण: org.hibernate।एनोटेशन अपवाद: @OneToMany या @ManyToMany का उपयोग एक अप्रयुक्त वर्ग ' –

12

हाइबरनेट (और जेपीए) सीधे PostgreSQL सरणी प्रकार मैप नहीं कर सकते हैं: तो, मैं थोड़ा तुम वर्ग बदल दिया है। See this question कैसे आगे बढ़ना है यदि आपको वास्तव में अपनी डेटाबेस संरचना को बनाए रखने की आवश्यकता है। This thread में आवश्यक कस्टम प्रकार का एक उदाहरण है।

यदि आप अपनी स्कीमा बदल सकते हैं, तो आप संग्रह को संभालने के लिए एक अतिरिक्त तालिका बनाने के लिए हाइबरनेट बना सकते हैं - List<Integer>। फिर, के संस्करण के आधार का उपयोग कर रहे हाइबरनेट:

5

हाइबरनेट केवल आदिम प्रकार मैप कर सकते हैं। हाइबरनेट जार पैकेज के org.hibernate.type फ़ोल्डर के अंतर्गत जांचें। int सरणी उनमें से एक नहीं है। तो आपको एक कस्टम प्रकार लिखना होगा जो UserType इंटरफ़ेस को कार्यान्वित कर सकता है।

public class MyClass{ 
    private Long id; 
    private String name; 
    private Integer[] values; 

    @Type(type = "com.usertype.IntArrayUserType") 
    public Integer[] getValues(){ 
     return values; 
    } 

    public void setValues(Integer[] values){ 
     this.values = values; 
    } 
} 

IntArrayUserType.class

package com.usertype.IntArrayUserType; 

public class IntArrayUserType implements UserType { 

protected static final int[] SQL_TYPES = { Types.ARRAY }; 

@Override 
public Object assemble(Serializable cached, Object owner) throws HibernateException { 
    return this.deepCopy(cached); 
} 

@Override 
public Object deepCopy(Object value) throws HibernateException { 
    return value; 
} 

@Override 
public Serializable disassemble(Object value) throws HibernateException { 
    return (Integer[]) this.deepCopy(value); 
} 

@Override 
public boolean equals(Object x, Object y) throws HibernateException { 

    if (x == null) { 
     return y == null; 
    } 
    return x.equals(y); 
} 

@Override 
public int hashCode(Object x) throws HibernateException { 
    return x.hashCode(); 
} 

@Override 
public boolean isMutable() { 
    return true; 
} 

@Override 
public Object nullSafeGet(ResultSet resultSet, String[] names, SessionImplementor session, Object owner) 
     throws HibernateException, SQLException { 
    if (resultSet.wasNull()) { 
     return null; 
    } 
    if(resultSet.getArray(names[0]) == null){ 
     return new Integer[0]; 
    } 

    Array array = resultSet.getArray(names[0]); 
    Integer[] javaArray = (Integer[]) array.getArray(); 
    return javaArray; 
} 

@Override 
public void nullSafeSet(PreparedStatement statement, Object value, int index, SessionImplementor session) 
     throws HibernateException, SQLException { 
    Connection connection = statement.getConnection(); 
    if (value == null) { 
     statement.setNull(index, SQL_TYPES[0]); 
    } else { 
     Integer[] castObject = (Integer[]) value; 
     Array array = connection.createArrayOf("integer", castObject); 
     statement.setArray(index, array); 
    } 
} 

@Override 
public Object replace(Object original, Object target, Object owner)  throws HibernateException { 
    return original; 
} 

@Override 
public Class<Integer[]> returnedClass() { 
    return Integer[].class; 
} 

@Override 
public int[] sqlTypes() { 
    return new int[] { Types.ARRAY }; 
} 

आप कुछ इस तरह जोड़ सकते हैं जब आप MyClass इकाई के लिए क्वेरी: जैसा कि मैंने this article में विस्तार से बताया

Type intArrayType = new TypeLocatorImpl(new TypeResolver()).custom(IntArrayUserType.class); 
Query query = getSession().createSQLQuery("select values from MyClass") 
    .addScalar("values", intArrayType); 
List<Integer[]> results = (List<Integer[]>) query.list(); 
+0

को लक्षित करना क्या आप इसे उत्पादन में उपयोग करते हैं? क्या यह आपके लिए काम करता है? – corsiKa

+0

हां यह उत्पादन में काम कर रहा है। मैंने इस स्निपेट को अपने कामकाजी कोड से कॉपी किया है – user3820369

0

, साथ एक सरणी मानचित्रण हाइबरनेट को एक कस्टम प्रकार की आवश्यकता होती है।

public class ArraySqlTypeDescriptor 
    implements SqlTypeDescriptor { 

    public static final ArraySqlTypeDescriptor INSTANCE = 
     new ArraySqlTypeDescriptor(); 

    @Override 
    public int getSqlType() { 
     return Types.ARRAY; 
    } 

    @Override 
    public boolean canBeRemapped() { 
     return true; 
    } 

    @Override 
    public <X> ValueBinder<X> getBinder(
     JavaTypeDescriptor<X> javaTypeDescriptor) { 
     return new BasicBinder<X>(javaTypeDescriptor, this) { 
      @Override 
      protected void doBind(
        PreparedStatement st, 
        X value, 
        int index, 
        WrapperOptions options 
       ) throws SQLException { 

       AbstractArrayTypeDescriptor<Object> abstractArrayTypeDescriptor = 
        (AbstractArrayTypeDescriptor<Object>) 
         javaTypeDescriptor; 

       st.setArray( 
        index, 
        st.getConnection().createArrayOf(
         abstractArrayTypeDescriptor.getSqlArrayType(), 
         abstractArrayTypeDescriptor.unwrap( 
          value, 
          Object[].class, 
          options 
         ) 
        ) 
       ); 
      } 

      @Override 
      protected void doBind(
        CallableStatement st, 
        X value, 
        String name, 
        WrapperOptions options 
       ) throws SQLException { 
       throw new UnsupportedOperationException( 
        "Binding by name is not supported!" 
       ); 
      } 
     }; 
    } 

    @Override 
    public <X> ValueExtractor<X> getExtractor(
     final JavaTypeDescriptor<X> javaTypeDescriptor) { 
     return new BasicExtractor<X>(javaTypeDescriptor, this) { 
      @Override 
      protected X doExtract(
        ResultSet rs, 
        String name, 
        WrapperOptions options 
       ) throws SQLException { 
       return javaTypeDescriptor.wrap(
        rs.getArray(name), 
        options 
       ); 
      } 

      @Override 
      protected X doExtract(
        CallableStatement statement, 
        int index, 
        WrapperOptions options 
       ) throws SQLException { 
       return javaTypeDescriptor.wrap(
        statement.getArray(index), 
        options 
       ); 
      } 

      @Override 
      protected X doExtract(
        CallableStatement statement, 
        String name, 
        WrapperOptions options 
       ) throws SQLException { 
       return javaTypeDescriptor.wrap(
        statement.getArray(name), 
        options 
       ); 
      } 
     }; 
    } 
} 

और IntArrayTypeDescriptor:

public class IntArrayTypeDescriptor 
     extends AbstractArrayTypeDescriptor<int[]> { 

    public static final IntArrayTypeDescriptor INSTANCE = 
     new IntArrayTypeDescriptor(); 

    public IntArrayTypeDescriptor() { 
     super(int[].class); 
    } 

    @Override 
    protected String getSqlArrayType() { 
     return "integer"; 
    } 
} 

जावा के थोक

public class IntArrayType 
     extends AbstractSingleColumnStandardBasicType<int[]> 
     implements DynamicParameterizedType { 

    public IntArrayType() { 
     super( 
      ArraySqlTypeDescriptor.INSTANCE, 
      IntArrayTypeDescriptor.INSTANCE 
     ); 
    } 

    public String getName() { 
     return "int-array"; 
    } 

    @Override 
    protected boolean registerUnderJavaType() { 
     return true; 
    } 

    @Override 
    public void setParameterValues(Properties parameters) { 
     ((IntArrayTypeDescriptor) 
      getJavaTypeDescriptor()) 
      .setParameterValues(parameters); 
    } 
} 

तुम भी ArraySqlTypeDescriptor की जरूरत है:

तो, आप IntArrayType इस तरह परिभाषित संभालने टू-जेडीबीसी प्रकार हैंडलिंगमें शामिल है 23,210 आधार वर्ग:

public abstract class AbstractArrayTypeDescriptor<T> 
     extends AbstractTypeDescriptor<T> 
     implements DynamicParameterizedType { 

    private Class<T> arrayObjectClass; 

    @Override 
    public void setParameterValues(Properties parameters) { 
     arrayObjectClass = ((ParameterType) parameters 
      .get(PARAMETER_TYPE)) 
      .getReturnedClass(); 

    } 

    public AbstractArrayTypeDescriptor(Class<T> arrayObjectClass) { 
     super( 
      arrayObjectClass, 
      (MutabilityPlan<T>) new MutableMutabilityPlan<Object>() { 
       @Override 
       protected T deepCopyNotNull(Object value) { 
        return ArrayUtil.deepCopy(value); 
       } 
      } 
     ); 
     this.arrayObjectClass = arrayObjectClass; 
    } 

    @Override 
    public boolean areEqual(Object one, Object another) { 
     if (one == another) { 
      return true; 
     } 
     if (one == null || another == null) { 
      return false; 
     } 
     return ArrayUtil.isEquals(one, another); 
    } 

    @Override 
    public String toString(Object value) { 
     return Arrays.deepToString((Object[]) value); 
    } 

    @Override 
    public T fromString(String string) { 
     return ArrayUtil.fromString(
      string, 
      arrayObjectClass 
     ); 
    } 

    @SuppressWarnings({ "unchecked" }) 
    @Override 
    public <X> X unwrap(
      T value, 
      Class<X> type, 
      WrapperOptions options 
     ) { 
     return (X) ArrayUtil.wrapArray(value); 
    } 

    @Override 
    public <X> T wrap(
      X value, 
      WrapperOptions options 
     ) { 
     if(value instanceof Array) { 
      Array array = (Array) value; 
      try { 
       return ArrayUtil.unwrapArray( 
        (Object[]) array.getArray(), 
        arrayObjectClass 
       ); 
      } 
      catch (SQLException e) { 
       throw new IllegalArgumentException(e); 
      } 
     } 
     return (T) value; 
    } 

    protected abstract String getSqlArrayType(); 
} 

AbstractArrayTypeDescriptorArrayUtil पर निर्भर करता है जावा सरणी गहरी नकल को संभालने के लिए, लपेटकर और तर्क unwrapping।

अब, आप कर रहे हैं मानचित्रण इस तरह दिखेगा:

@Entity(name = "Event") 
@Table(name = "event") 
@TypeDef(
     name = "int-array", 
     typeClass = IntArrayType.class 
) 
public static class Event 
    extends BaseEntity { 

    @Type(type = "int-array") 
    @Column(
     name = "sensor_values", 
     columnDefinition = "integer[]" 
    ) 
    private int[] sensorValues; 

    //Getters and setters omitted for brevity 
}