[Java] التعداد خريطة في JPA مع قيم ثابتة؟


Answers

هذا ممكن الآن مع JPA 2.1:

@Column(name = "RIGHT")
@Enumerated(EnumType.STRING)
private Right right;

تفاصيل أكثر:

Question

أنا أبحث عن طرق مختلفة لتخطيط التعداد باستخدام JPA. أرغب بشكل خاص في تعيين القيمة الصحيحة لكل إدخال تعداد ولحفظ قيمة الأعداد الصحيحة فقط.

@Entity
@Table(name = "AUTHORITY_")
public class Authority implements Serializable {

  public enum Right {
      READ(100), WRITE(200), EDITOR (300);

      private int value;

      Right(int value) { this.value = value; }

      public int getValue() { return value; }
  };

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  @Column(name = "AUTHORITY_ID")
  private Long id;

  // the enum to map : 
  private Right right;
}

الحل البسيط هو استخدام التعليق التوضيحي مع EnumType.ORDINAL:

@Column(name = "RIGHT")
@Enumerated(EnumType.ORDINAL)
private Right right;

ولكن في هذه الحالة ، تقوم JPA بتعيين فهرس التعداد (0،1،2) وليس القيمة التي أريدها (100،200،300).

لا يبدو أن اثنين من الحلول التي وجدتها بسيطة ...

الحل الأول

يستخدم الحل المقترح هنا ،PrePersist وPostLoad لتحويل التعداد إلى حقل آخر ووضع علامة على حقل التعداد كنقل مؤقت:

@Basic
private int intValueForAnEnum;

@PrePersist
void populateDBFields() {
  intValueForAnEnum = right.getValue();
}

@PostLoad
void populateTransientFields() {
  right = Right.valueOf(intValueForAnEnum);
}

الحل الثاني

اقترح الحل الثاني المقترح هنا كائن تحويل عام ، ولكن لا يزال يبدو ثقيلًا وموجهاً إلى السبات (يبدو أنType غير موجود في Java EE):

@Type(
    type = "org.appfuse.tutorial.commons.hibernate.GenericEnumUserType",
    parameters = {
            @Parameter(
                name  = "enumClass",                      
                value = "Authority$Right"),
            @Parameter(
                name  = "identifierMethod",
                value = "toInt"),
            @Parameter(
                name  = "valueOfMethod",
                value = "fromInt")
            }
)

هل هناك حلول أخرى؟

لدي العديد من الأفكار في أذهاننا ولكن لا أعرف ما إذا كانت موجودة في JPA:

  • استخدام أساليب setter و getter للعضو الصحيح في فئة Authority عند تحميل كائن Authority وحفظه
  • فكرة مماثلة هي أن نقول JPA ما هي طرق التعداد الصحيح لتحويل التعداد إلى int و int enum
  • لأنني أستخدم Spring ، هل هناك أي طريقة لإخبار JPA باستخدام محول محدد (RightEditor)؟



ربما قريبة من التعليمات البرمجية ذات الصلة باسكال

@Entity
@Table(name = "AUTHORITY_")
public class Authority implements Serializable {

    public enum Right {
        READ(100), WRITE(200), EDITOR(300);

        private Integer value;

        private Right(Integer value) {
            this.value = value;
        }

        // Reverse lookup Right for getting a Key from it's values
        private static final Map<Integer, Right> lookup = new HashMap<Integer, Right>();
        static {
            for (Right item : Right.values())
                lookup.put(item.getValue(), item);
        }

        public Integer getValue() {
            return value;
        }

        public static Right getKey(Integer value) {
            return lookup.get(value);
        }

    };

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "AUTHORITY_ID")
    private Long id;

    @Column(name = "RIGHT_ID")
    private Integer rightId;

    public Right getRight() {
        return Right.getKey(this.rightId);
    }

    public void setRight(Right right) {
        this.rightId = right.getValue();
    }

}



المشكلة هي ، كما أعتقد ، أن JPA لم يتم إدراكها أبداً مع الفكرة القائلة بأنه يمكن أن يكون لدينا مخطط موجود مسبقاً موجود بالفعل.

أعتقد أن هناك نوعين من أوجه القصور الرئيسية الناتجة عن ذلك ، خاصة في Enum:

  1. قيود استخدام name () و ordinal (). لماذا لا تضع علامة فقط على getter بـId ، كما نفعل معEntity؟
  2. يوجد تمثيل Enum عادة في قاعدة البيانات للسماح بالارتباط مع جميع أنواع البيانات الوصفية ، بما في ذلك الاسم الصحيح ، الاسم الوصفي ، ربما شيء مع التعريب وما إلى ذلك. نحتاج إلى سهولة استخدام التعداد جنبًا إلى جنب مع مرونة الكيان.

مساعدة قضيتي والتصويت على JPA_SPEC-47

هل هذا لن يكون أكثر أناقة من استخدامConverter لحل المشكلة؟

// Note: this code won't work!!
// it is just a sample of how I *would* want it to work!
@Enumerated
public enum Language {
  ENGLISH_US("en-US"),
  ENGLISH_BRITISH("en-BR"),
  FRENCH("fr"),
  FRENCH_CANADIAN("fr-CA");
  @ID
  private String code;
  @Column(name="DESCRIPTION")
  private String description;

  Language(String code) {
    this.code = code;
  }

  public String getCode() {
    return code;
  }

  public String getDescription() {
    return description;
  }
}



Links