كيفية استخدام التعداد مع JPA كعضو بيانات في الكيان المستمر؟
سؤال
يرجى أفضل الممارسات و "كيفية" لاستخدام التعداد مع JPA كعضو بيانات في الكيان المستمر. ما هو أفضل الممارسات؟ أريد أن أستمر "C" ، "O" من التعداد. (الرموز). إذا لم يكن هذا هو النهج الصحيح من فضلك اقترح.
تعداد الدفء هو -
public enum Status{
CLOSED ("C")
OPEN ("O")
private final int value;
private Status(final int pValue){
this.value = pValue;
}
public int value(){
return this.value;
}
المحلول
الحل المتوقع:تعداد الدفء:
public enum Status {
CLOSED(1), NEW(2), RUNNING(3), OPEN(4), ADDED(5), SUCEESS(-1), DONE(0);
private int code;
private Status(int code) {
this.code = code;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public static Status valueOf(int i){
for (Status s : values()){
if (s.code == i){
return s;
}
}
throw new IllegalArgumentException("No matching constant for " + i);
}
}
تعريف الكيان:
@Entity
@NamedQuery(name="Process.findAll", query="select p from Process p ")
public class Process {
@Id
private long id;
private String name;
@Transient
private transient Status status; //actual enum; not stored in db
@Column(name="STATUS")
private int statusCode; // enum code gets stored in db
@PrePersist
void populateDBFields(){
statusCode = status.getCode();
}
@PostLoad
void populateTransientFields(){
status = Status.valueOf(statusCode);
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Status getStatus() {
return status;
}
public void setStatus(Status status) {
this.status = status;
}
}
نصائح أخرى
نحن نستمر في التعداد كقواسل. يستخدم @Enumerated(EnumType.STRING)
لاستخدام تمثيل السلسلة (بدلاً من رمز التعداد التلقائي). هذا يجعل بياناتك في DB أكثر قابلية للقراءة.
إذا كنت بحاجة حقًا إلى تعيين التعدادات إلى رموز خاصة (الرمز القديم وما شابه) ، فستحتاج إلى رسم خرائط مخصص. أولا فئة أساسية تقوم بتعيين تعداد DB والعودة:
import java.io.Serializable;
import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.usertype.UserType;
public abstract class CustomEnumType implements UserType
{
public Object deepCopy (Object value) throws HibernateException
{
return value;
}
public Serializable disassemble (Object value) throws HibernateException
{
return (Serializable)value;
}
public Object assemble (Serializable cached, Object owner)
throws HibernateException
{
return cached;
}
public boolean equals (Object x, Object y) throws HibernateException
{
// Correct for Enums
return x == y;
}
public int hashCode (Object x) throws HibernateException
{
return x.hashCode ();
}
public boolean isMutable ()
{
return false;
}
public Object replace (Object original, Object target, Object owner)
throws HibernateException
{
return original;
}
public int[] sqlTypes ()
{
return new int[]{ Hibernate.STRING.sqlType() };
}
}
الآن امتداد يستخدم DBenum لتعيين القيم لتعدادك إلى DB والعودة:
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.apache.log4j.Logger;
public abstract class DBEnumType extends CustomEnumType
{
private final static Logger log = Logger.getLogger(DBEnumType.class);
private static final boolean IS_VALUE_TRACING_ENABLED = log.isTraceEnabled();
public Object nullSafeGet (ResultSet rs, String[] names, Object owner)
throws HibernateException, SQLException
{
String value = rs.getString (names[0]);
if (rs.wasNull ())
return null;
return toEnum (value);
}
public abstract Object toEnum (String value);
public void nullSafeSet (PreparedStatement st, Object value, int index)
throws HibernateException, SQLException
{
if (value == null)
st.setNull (index, Hibernate.STRING.sqlType ());
else
{
DBEnum dbEnum = (DBEnum)value;
value = dbEnum.getDBCode();
st.setString (index, dbEnum.getDBCode());
}
if (IS_VALUE_TRACING_ENABLED)
{
log.trace (getClass().getName()+" "+value);
}
}
}
الواجهة:
public interface DBEnum
{
public String getDBCode ();
}
أخيرًا ، يجب أن تمتد DBEnumType
لكل نوع تعداد تريد تعيينه:
public class DBEnumCardType extends DBEnumType
{
public Class returnedClass ()
{
return Status.class;
}
public Object toEnum (String value)
{
return Status.fromDBCode (value);
}
}
في Status
, ، يجب عليك تنفيذ الطريقة الثابتة التي تقوم بتخطيط رموز DB إلى التعداد:
private final static Map<String, Status> dbCode2Enum = new HashMap<String, Status> ();
static {
for (Status enm: Status.values ())
{
String key = enm.getDBCode ();
if (dbCode2Enum.containsKey (key))
throw new ShouldNotHappenException ("Duplicate key "+key+" in "+enm.getClass ());
dbCode2Enum.put (key, enm);
}
}
private String dbCode;
private Status (String dbCode)
{
this.dbCode = dbCode;
}
public String getDBCode ()
{
return dbCode;
}
public static Status fromDBCode (String dbCode)
{
if (dbCode == null)
return null;
Status result = dbCode2Enum.get (dbCode);
if (result == null)
throw new ShouldNotHappenException ("Can't find key "+dbCode+" in "+Status.class);
return result;
}
أخيرًا ، يجب عليك استخدام التعليق التوضيحي @org.hibernate.annotations.Type()
لإخبار Hibernate لاستخدام رسم الخرائط المخصصة.
الخلاصة: لا تستخدم الرموز المخصصة. إنهم يولدون الكثير من رمز لوحة الغلايات الغبي الذي لا يمكنك عوامله.
تعتبر التعدادات افتراضيًا تدعمها JPA ، لكن المشكلة هي أنها تستخدم أوامر القيم افتراضيًا لا يمكنك التحكم فيها. لحل هذا ، يمكنك استخدام القليل من المنطق على مستقلين getter الخاص بك.
@Column(name = "KIRSAL_METROPOL")
private String someEnum;
public YourEnum getSomeEnum() {
return EnumUtils.getEnum(YourEnum.class, this.someEnum);
}
public void setSomeEnum(YourEnum someEnum) {
this. someEnum = EnumUtils.getValue(someEnum);
}
يجب أن تقوم التعدادات بالتحويل ...