แม็พ enum ใน JPA ด้วยค่าคงที่หรือไม่


192

ฉันกำลังมองหาวิธีต่างๆในการแมป enum โดยใช้ JPA ฉันต้องการตั้งค่าจำนวนเต็มของแต่ละรายการ enum และบันทึกเฉพาะค่าจำนวนเต็ม

@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 จะแมปดัชนี enum (0,1,2) และไม่ใช่ค่าที่ฉันต้องการ (100,200,300)

โซลูชันที่สองที่ฉันพบดูเหมือนจะไม่ง่าย ...

ทางออกแรก

โซลูชันที่เสนอที่นี่ใช้ @PrePersist และ @PostLoad เพื่อแปลง enum เป็นฟิลด์อื่นและทำเครื่องหมายฟิลด์ enum เป็น transient:

@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 Class เมื่อทำการโหลดและบันทึกออบเจกต์ Authority
  • ความคิดที่เท่าเทียมกันจะบอก JPA ว่าอะไรคือวิธีการ Right enum ในการแปลง enum เป็น int และ int เป็น enum
  • เพราะฉันใช้สปริงมีวิธีบอก JPA ให้ใช้ตัวแปลงเฉพาะ (RightEditor) หรือไม่

7
เป็นเรื่องแปลกที่บางครั้งการใช้ ORDINAL จะเปลี่ยนสถานที่ของรายการในการแจงนับและฐานข้อมูลจะกลายเป็นหายนะ
Natasha KP

2
ไม่เหมือนกันจะนำไปใช้โดยใช้ชื่อ - ใครบางคนอาจมีการเปลี่ยนแปลงชื่อ enum (s) และพวกเขาก็เป็นอีกครั้งที่ออกจากซิงค์กับฐานข้อมูล ...
topchef

2
ฉันเห็นด้วยกับ @NatashaKP อย่าใช้ลำดับ สำหรับการเปลี่ยนชื่อไม่มีสิ่งนั้น คุณกำลังลบ Enum เก่าและเพิ่มชื่อใหม่ด้วยชื่อใหม่ดังนั้นใช่ข้อมูลที่เก็บไว้ใด ๆ จะไม่ซิงค์กัน (ความหมายอาจ: P)
Svend Hansen

ใช่มี 5 โซลูชั่นที่ฉันรู้ ดูคำตอบของฉันด้านล่างซึ่งฉันมีคำตอบโดยละเอียด
Chris Ritchie

คำตอบ:


168

สำหรับรุ่นก่อนหน้านี้กว่า JPA 2.1 JPA ให้เพียงสองวิธีที่จะจัดการกับ enums โดยพวกเขาหรือพวกเขาname ordinalและ JPA มาตรฐานไม่รองรับประเภทที่กำหนดเอง ดังนั้น:

  • หากคุณต้องการทำการแปลงประเภทที่กำหนดเองคุณจะต้องใช้ส่วนขยายของผู้ให้บริการ (ด้วย Hibernate UserType, EclipseLink Converterฯลฯ ) (ทางออกที่สอง) ~ หรือ ~
  • คุณจะต้องใช้เคล็ดลับ @PrePersist และ @PostLoad (โซลูชันแรก) ~ หรือ ~
  • ใส่คำอธิบายประกอบ getter และ setter เพื่อรับและส่งคืนintค่า ~ หรือ ~
  • ใช้แอตทริบิวต์จำนวนเต็มที่ระดับเอนทิตีและทำการแปลใน getters และ setters

ฉันจะแสดงตัวเลือกล่าสุด (นี่คือการใช้งานพื้นฐานปรับแต่งตามต้องการ):

@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; }

        public static Right parse(int id) {
            Right right = null; // Default
            for (Right item : Right.values()) {
                if (item.getValue()==id) {
                    right = item;
                    break;
                }
            }
            return right;
        }

    };

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

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

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

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

}

50
JPA ที่น่าเศร้าก็ไม่มีการสนับสนุนในเรื่องนี้
Jaime Hablutzel

20
@jaime เห็นด้วย! มันบ้าที่จะคิดว่านักพัฒนาอาจต้องการคง enum เป็นค่าของหนึ่งในสาขา / คุณสมบัติของมันแทนค่า int หรือชื่อของมัน? ทั้งสองอย่างนั้นมี "ความเปราะบาง" และการปรับโครงสร้างใหม่ที่ไม่เป็นมิตร และการใช้ชื่อยังถือว่าคุณใช้หลักการตั้งชื่อเดียวกันทั้งใน Java และฐานข้อมูล ยกตัวอย่างเพศ ที่อาจถูกกำหนดเป็นเพียง 'M' หรือ 'F' ในฐานข้อมูล แต่ไม่ควรป้องกันฉันจากการใช้ออฟเฟมเพศชายและเพศหญิงใน Java แทนที่จะเป็นเพศชายหรือเพศชาย
spaaarky21

2
ฉันเดาเหตุผลอาจเป็นได้ว่าชื่อและลำดับที่ทั้งสองรับประกันว่าจะไม่ซ้ำกันในขณะที่ค่าหรือเขตข้อมูลอื่น ๆ ไม่ได้ มันเป็นความจริงที่ว่าคำสั่งนั้นสามารถเปลี่ยนแปลงได้ (อย่าใช้ลำดับ) และชื่อก็สามารถเปลี่ยนได้เช่นกัน (อย่าเปลี่ยนชื่อ enum: P) แต่มีค่าอื่น ๆ ... ฉันไม่แน่ใจว่าฉันเห็น ความคุ้มค่าสูงสุดด้วยการเพิ่มความสามารถในการจัดเก็บค่าที่แตกต่าง
Svend Hansen

2
ที่จริงแล้วฉันเห็นค่า ... ฉันจะลบส่วนหนึ่งของความคิดเห็นของฉันที่ด้านบนถ้าฉันยังคงสามารถแก้ไขได้: P: D
Svend Hansen

13
JPA2.1 จะให้การสนับสนุนตัวแปลงโดยพื้นฐาน โปรดดูsomethoughtsonjava.blogspot.fi/2013/10/…
drodil

69

ตอนนี้เป็นไปได้ด้วย JPA 2.1:

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

รายละเอียดเพิ่มเติม:


2
สิ่งที่เป็นไปได้ในตอนนี้? แน่นอนว่าเราสามารถใช้@Converterแต่enumควรได้รับการจัดการอย่างหรูหรามากขึ้นนอกกรอบ!
YoYo

4
"คำตอบ" อ้างอิง 2 ลิงค์ที่พูดถึงการใช้AttributeConverterBUT ราคารหัสบางอย่างที่ไม่มีการเรียงลำดับและไม่ตอบ OP

@ DN1 รู้สึกอิสระที่จะปรับปรุง
Tvaroh

1
มันเป็น "คำตอบ" ของคุณดังนั้นคุณควร "ปรับปรุง" มีคำตอบสำหรับAttributeConverter

1
ทำงานอย่างสมบูรณ์แบบหลังจากเพิ่ม:@Convert(converter = Converter.class) @Enumerated(EnumType.STRING)
Kaushal28

23

จาก JPA 2.1 คุณสามารถใช้AttributeConverter

สร้างคลาสที่แจกแจงเช่น:

public enum NodeType {

    ROOT("root-node"),
    BRANCH("branch-node"),
    LEAF("leaf-node");

    private final String code;

    private NodeType(String code) {
        this.code = code;
    }

    public String getCode() {
        return code;
    }
}

และสร้างตัวแปลงดังนี้:

import javax.persistence.AttributeConverter;
import javax.persistence.Converter;

@Converter(autoApply = true)
public class NodeTypeConverter implements AttributeConverter<NodeType, String> {

    @Override
    public String convertToDatabaseColumn(NodeType nodeType) {
        return nodeType.getCode();
    }

    @Override
    public NodeType convertToEntityAttribute(String dbData) {
        for (NodeType nodeType : NodeType.values()) {
            if (nodeType.getCode().equals(dbData)) {
                return nodeType;
            }
        }

        throw new IllegalArgumentException("Unknown database value:" + dbData);
    }
}

ในเอนทิตีที่คุณต้องการ:

@Column(name = "node_type_code")

คุณโชคดีที่@Converter(autoApply = true)อาจแตกต่างกันไปตามภาชนะ แต่ผ่านการทดสอบการทำงานกับ Wildfly 8.1.0 ถ้ามันไม่ทำงานคุณสามารถเพิ่ม@Convert(converter = NodeTypeConverter.class)ในคอลัมน์คลาสกิจการ


"values ​​()" ควรเป็น "NodeType.values ​​()"
Curtis Yallop

17

วิธีที่ดีที่สุดคือการจับคู่ ID เฉพาะกับ enum แต่ละประเภทดังนั้นหลีกเลี่ยงข้อผิดพลาดของ ORDINAL และ STRING ดูโพสต์นี้ซึ่งสรุป 5 วิธีที่คุณสามารถแมป enum

นำมาจากลิงค์ด้านบน:

1 & 2 ใช้ @Enumerated

ขณะนี้มี 2 วิธีที่คุณสามารถแมป enums ภายในเอนทิตี JPA ของคุณโดยใช้คำอธิบายประกอบแบบ @Enumerated น่าเสียดายที่ EnumType.STRING และ EnumType.ORDINAL มีข้อ จำกัด

หากคุณใช้ EnumType.String การเปลี่ยนชื่อ enum ประเภทใดประเภทหนึ่งจะทำให้ค่า enum ของคุณไม่ซิงค์กับค่าที่บันทึกไว้ในฐานข้อมูล หากคุณใช้ EnumType.ORDINAL การลบหรือการเรียงลำดับชนิดใหม่ภายใน enum ของคุณจะทำให้ค่าที่บันทึกไว้ในฐานข้อมูลเพื่อจับคู่กับประเภท enum ที่ไม่ถูกต้อง

ตัวเลือกทั้งสองนี้มีความเปราะบาง หาก enum ถูกแก้ไขโดยไม่ทำการย้ายฐานข้อมูลคุณสามารถเปลี่ยนความสมบูรณ์ของข้อมูลของคุณ

3. ระยะเวลาการเรียกกลับ

วิธีแก้ปัญหาที่เป็นไปได้คือการใช้คำอธิบายประกอบรอบการโทรกลับ JPA, @PrePersist และ @PostLoad สิ่งนี้ให้ความรู้สึกที่น่าเกลียดเพราะคุณจะมีตัวแปรสองตัวในเอนทิตีของคุณ หนึ่งการแมปค่าที่เก็บไว้ในฐานข้อมูลและอื่น ๆ การ enum จริง

4. การจับคู่ ID เฉพาะกับ enum แต่ละประเภท

โซลูชันที่ต้องการคือแมป enum ของคุณกับค่าคงที่หรือ ID ที่กำหนดไว้ภายใน enum การจับคู่กับค่าที่กำหนดไว้ล่วงหน้าจะทำให้รหัสของคุณแข็งแกร่งยิ่งขึ้น การแก้ไขคำสั่งประเภท enums หรือการเปลี่ยนชื่อจะไม่ทำให้เกิดผลกระทบใด ๆ

5. การใช้ Java EE7 @Convert

หากคุณใช้ JPA 2.1 คุณมีตัวเลือกในการใช้คำอธิบายประกอบ @Convert ใหม่ สิ่งนี้ต้องการการสร้างคลาสตัวแปลงซึ่งมีคำอธิบายประกอบด้วย @Converter ซึ่งคุณจะต้องกำหนดค่าที่จะบันทึกลงในฐานข้อมูลสำหรับแต่ละประเภท enum ภายในเอนทิตีของคุณคุณจะใส่คำอธิบายประกอบ enum ด้วย @Convert

การตั้งค่าของฉัน: (หมายเลข 4)

เหตุผลที่ฉันต้องการกำหนด ID ของฉันภายใน enum เมื่อเทียบกับการใช้ตัวแปลงคือ encapsulation ที่ดี เฉพาะประเภท enum เท่านั้นที่ควรทราบ ID และมีเพียงเอนทิตีที่ควรทราบเกี่ยวกับวิธีจับคู่ enum กับฐานข้อมูล

ดูโพสต์ต้นฉบับสำหรับตัวอย่างรหัส


1
javax.persistence.Converter นั้นง่ายและด้วย @Converter (autoApply = true) จะช่วยให้คลาสของโดเมนปราศจากการเพิ่มความคิดเห็น @Convert
Rostislav Matl

9

ฉันคิดว่าปัญหาคือ JPA ที่ไม่เคยมีแนวคิดในใจว่าเราสามารถมี Schema ที่ซับซ้อนมาก่อนได้แล้ว

ฉันคิดว่ามีข้อบกพร่องหลักสองประการที่เป็นผลมาจากสิ่งนี้โดยเฉพาะกับ Enum:

  1. ข้อ จำกัด ของการใช้ชื่อ () และลำดับ () ทำไมไม่ทำเครื่องหมายเพียงผู้ทะเยอทะยานด้วย @Id วิธีที่เราทำกับ @Entity
  2. Enum มีตัวแทนอยู่ในฐานข้อมูลเพื่ออนุญาตให้มีการเชื่อมโยงกับข้อมูลเมตาทุกประเภทรวมถึงชื่อที่เหมาะสมชื่อที่สื่อความหมายบางทีสิ่งที่มีการแปล ฯลฯ เราต้องการความสะดวกในการใช้ Enum รวมกับความยืดหยุ่นของ Entity

ช่วยสาเหตุและลงคะแนนใน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;
  }
}

4

อาจเป็นไปได้ว่าเกี่ยวข้องกับรหัสปิดของปาสกาล

@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();
    }

}

3

ฉันจะทำสิ่งต่อไปนี้:

ประกาศ enum แยกในไฟล์ของตัวเอง:

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

      private int value;

      private RightEnum (int value) { this.value = value; }


      @Override
      public static Etapa valueOf(Integer value){
           for( RightEnum r : RightEnum .values() ){
              if ( r.getValue().equals(value))
                 return r;
           }
           return null;//or throw exception
     }

      public int getValue() { return value; }


}

ประกาศเอนทิตี JPA ใหม่ที่ชื่อ Right

@Entity
public class Right{
    @Id
    private Integer id;
    //FIElDS

    // constructor
    public Right(RightEnum rightEnum){
          this.id = rightEnum.getValue();
    }

    public Right getInstance(RightEnum rightEnum){
          return new Right(rightEnum);
    }


}

คุณจะต้องใช้ตัวแปลงเพื่อรับค่านี้ (JPA 2.1 เท่านั้นและมีปัญหาฉันจะไม่พูดถึงที่นี่กับ enum เหล่านี้เพื่อยืนยันโดยตรงโดยใช้ตัวแปลงดังนั้นมันจะเป็นถนนทางเดียวเท่านั้น)

import mypackage.RightEnum;
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;

/**
 * 
 * 
 */
@Converter(autoApply = true)
public class RightEnumConverter implements AttributeConverter<RightEnum, Integer>{

    @Override //this method shoudn´t be used, but I implemented anyway, just in case
    public Integer convertToDatabaseColumn(RightEnum attribute) {
        return attribute.getValue();
    }

    @Override
    public RightEnum convertToEntityAttribute(Integer dbData) {
        return RightEnum.valueOf(dbData);
    }

}

หน่วยงานผู้มีอำนาจ:

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


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

  // the **Entity** to map : 
  private Right right;

  // the **Enum** to map (not to be persisted or updated) : 
  @Column(name="COLUMN1", insertable = false, updatable = false)
  @Convert(converter = RightEnumConverter.class)
  private RightEnum rightEnum;

}

ด้วยการทำเช่นนี้คุณไม่สามารถตั้งค่าโดยตรงกับฟิลด์ enum อย่างไรก็ตามคุณสามารถตั้งค่าฟิลด์ขวาใน Authority โดยใช้

autorithy.setRight( Right.getInstance( RightEnum.READ ) );//for example

และหากคุณต้องการเปรียบเทียบคุณสามารถใช้:

authority.getRight().equals( RightEnum.READ ); //for example

อันไหนเจ๋งมากฉันคิดว่า มันไม่ถูกต้องทั้งหมดเนื่องจากตัวแปลงไม่ได้มีวัตถุประสงค์เพื่อใช้กับ enum ที่จริงแล้วเอกสารบอกว่าจะไม่ใช้เพื่อจุดประสงค์นี้คุณควรใช้คำอธิบายประกอบแบบ @Enumerated แทน ปัญหาคือมีเพียงสองชนิด enum: ORDINAL หรือ STRING แต่ ORDINAL นั้นยากและไม่ปลอดภัย


อย่างไรก็ตามหากมันไม่เป็นที่พอใจคุณคุณสามารถทำอะไรที่แฮ็คและเรียบง่ายขึ้นเล็กน้อย (หรือไม่)

มาดูกัน.

The RightEnum:

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

      private int value;

      private RightEnum (int value) { 
            try {
                  this.value= value;
                  final Field field = this.getClass().getSuperclass().getDeclaredField("ordinal");
                  field.setAccessible(true);
                  field.set(this, value);
             } catch (Exception e) {//or use more multicatch if you use JDK 1.7+
                  throw new RuntimeException(e);
            }
      }


      @Override
      public static Etapa valueOf(Integer value){
           for( RightEnum r : RightEnum .values() ){
              if ( r.getValue().equals(value))
                 return r;
           }
           return null;//or throw exception
     }

      public int getValue() { return value; }


}

และหน่วยงานผู้มีอำนาจ

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


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


  // the **Enum** to map (to be persisted or updated) : 
  @Column(name="COLUMN1")
  @Enumerated(EnumType.ORDINAL)
  private RightEnum rightEnum;

}

ในความคิดที่สองนี้มันไม่ได้เป็นสถานการณ์ที่สมบูรณ์แบบเพราะเราแฮ็กแอตทริบิวต์ลำดับ แต่มันเป็นรหัสที่เล็กกว่ามาก

ฉันคิดว่าข้อกำหนด JPA ควรรวม EnumType.ID โดยที่ข้อมูลกำกับ enum ควรมีหมายเหตุประกอบด้วย @EnumId หมายเหตุประกอบ


2

โซลูชันของตัวเองในการแก้ปัญหาการทำแผนที่ Enum JPA ประเภทนี้มีดังต่อไปนี้

ขั้นตอนที่ 1 - เขียนอินเตอร์เฟสต่อไปนี้ที่เราจะใช้สำหรับ enums ทั้งหมดที่เราต้องการแมปไปยังคอลัมน์ db:

public interface IDbValue<T extends java.io.Serializable> {

    T getDbVal();

}

ขั้นตอนที่ 2 - ปรับใช้ตัวแปลง JPA ทั่วไปที่กำหนดเองดังต่อไปนี้:

import javax.persistence.AttributeConverter;

public abstract class EnumDbValueConverter<T extends java.io.Serializable, E extends Enum<E> & IDbValue<T>>
        implements AttributeConverter<E, T> {

    private final Class<E> clazz;

    public EnumDbValueConverter(Class<E> clazz){
        this.clazz = clazz;
    }

    @Override
    public T convertToDatabaseColumn(E attribute) {
        if (attribute == null) {
            return null;
        }
        return attribute.getDbVal();
    }

    @Override
    public E convertToEntityAttribute(T dbData) {
        if (dbData == null) {
            return null;
        }
        for (E e : clazz.getEnumConstants()) {
            if (dbData.equals(e.getDbVal())) {
                return e;
            }
        }
        // handle error as you prefer, for example, using slf4j:
        // log.error("Unable to convert {} to enum {}.", dbData, clazz.getCanonicalName());
        return null;
    }

}

คลาสนี้จะแปลงค่า enum Eเป็นฟิลด์ฐานข้อมูลชนิดT(เช่นString) โดยใช้getDbVal()on enumEและในทางกลับกัน

ขั้นตอนที่ 3 - ให้ enum ดั้งเดิมใช้อินเทอร์เฟซที่เรากำหนดไว้ในขั้นตอนที่ 1:

public enum Right implements IDbValue<Integer> {
    READ(100), WRITE(200), EDITOR (300);

    private final Integer dbVal;

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

    @Override
    public Integer getDbVal() {
        return dbVal;
    }
}

ขั้นตอนที่ 4 - ขยายตัวแปลงของขั้นตอนที่ 2 สำหรับRightenum ของขั้นตอนที่ 3:

public class RightConverter extends EnumDbValueConverter<Integer, Right> {
    public RightConverter() {
        super(Right.class);
    }
}

ขั้นตอนที่ 5 - ขั้นตอนสุดท้ายคือการใส่คำอธิบายประกอบฟิลด์ในกิจการดังต่อไปนี้:

@Column(name = "RIGHT")
@Convert(converter = RightConverter.class)
private Right right;

ข้อสรุป

IMHO นี่เป็นวิธีการแก้ปัญหาที่สะอาดและหรูหราที่สุดหากคุณมี enums มากมายในการทำแผนที่และคุณต้องการใช้ฟิลด์เฉพาะของ enum เองเป็นค่าการทำแผนที่

สำหรับคนอื่น ๆ ทั้งหมดในโครงการของคุณที่ต้องการตรรกะการทำแผนที่ที่คล้ายกันคุณต้องทำซ้ำขั้นตอนที่ 3 ถึง 5 นั่นคือ:

  • ใช้อินเตอร์เฟสIDbValueบน enum ของคุณ
  • ขยาย EnumDbValueConverterด้วย 3 บรรทัดเท่านั้น (คุณสามารถทำได้ภายในเอนทิตีของคุณเพื่อหลีกเลี่ยงการสร้างคลาสแยก)
  • บันทึกย่อคุณลักษณะ enum ด้วย@Convertจากjavax.persistenceแพคเกจ

หวังว่านี่จะช่วยได้


1
public enum Gender{ 
    MALE, FEMALE 
}



@Entity
@Table( name="clienti" )
public class Cliente implements Serializable {
...

// **1 case** - If database column type is number (integer) 
// (some time for better search performance)  -> we should use 
// EnumType.ORDINAL as @O.Badr noticed. e.g. inserted number will
// index of constant starting from 0... in our example for MALE - 0, FEMALE - 1.
// **Possible issue (advice)**: you have to add the new values at the end of
// your enum, in order to keep the ordinal correct for future values.

@Enumerated(EnumType.ORDINAL)
    private Gender gender;


// **2 case** - If database column type is character (varchar) 
// and you want to save it as String constant then ->

@Enumerated(EnumType.STRING)
    private Gender gender;

...
}

// in all case on code level you will interact with defined 
// type of Enum constant but in Database level

กรณีแรก ( EnumType.ORDINAL)

╔════╦══════════════╦════════╗
 ID     NAME       GENDER 
╠════╬══════════════╬════════╣
  1  Jeff Atwood      0   
  2  Geoff Dalgas     0   
  3 Jarrod Jesica     1   
  4  Joel Lucy        1   
╚════╩══════════════╩════════╝

กรณีที่สอง ( EnumType.STRING)

╔════╦══════════════╦════════╗
 ID     NAME       GENDER 
╠════╬══════════════╬════════╣
  1  Jeff Atwood    MALE  
  2  Geoff Dalgas   MALE  
  3 Jarrod Jesica  FEMALE 
  4  Joel Lucy     FEMALE 
╚════╩══════════════╩════════╝
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.