Wyliczenia w Hibernate

82

Często przydatne jest posiadanie pola w DAO, którego wartość pochodzi z wyliczenia Java. Typowym przykładem jest DAO logowania, w którym zwykle masz pole charakteryzujące użytkownika jako „NORMALNY” lub „ADMINISTRATOR”. W Hibernate użyłbym następujących 2 obiektów, aby przedstawić tę relację w (pół) bezpieczny sposób:

class User {
    String username;
    String passwd;
    UserType type;
}

class UserType {
    private enum Type {ADMIN, NORMAL};
    private String type;

    //Setters/Getters for Hibernate
    public void setType(String type);
    public String getType();

    //Setters/Getters for user
    public void setUserType(UserType.Type t);
    public UserType.Type getUserType();

    public static UserType fromType(UserType.Type t);
}

To działa, ale uważam, że klasa UserType jest brzydka i wymaga zbyt dużej biurokracji, aby przechowywać tylko kilka wartości. W idealnym przypadku Hibernate powinien obsługiwać pola wyliczeniowe bezpośrednio i utworzyć dodatkową tabelę do przechowywania wartości wyliczenia.

Moje pytanie brzmi: czy istnieje sposób bezpośredniego mapowania klasy wyliczenia w Hibernate? Jeśli nie, czy mój wzór przedstawiania wyliczeń jest wystarczająco dobry, czy czegoś mi brakuje? Jakich innych wzorców używają ludzie?

Georgios Gousios
źródło

Odpowiedzi:

110

przy użyciu adnotacji hibernacji lub JPA:

class User {
   @Enumerated(EnumType.STRING)
   UserType type
}

UserType to po prostu standardowe wyliczenie języka Java 5.

Nie mogę sobie wyobrazić, że ogranicza się to tylko do adnotacji, ale tak naprawdę nie wiem, jak to zrobić z plikami HBM. Domyślam się, że może to być bardzo zależne od wersji, ale jestem prawie pewien, że wymagana jest hibernacja 3.2+.

edycja: jest to możliwe w hbm, ale jest trochę niechlujne, spójrz na ten wątek na forum

Gareth Davis
źródło
3
Czy @Enumerated (EnumType.ORDINAL), które mapowanie do int jest bardziej wydajne?
Lee Chee Kiam
4
prawdopodobnie jest bardziej wydajne, ale postawiłbym pieniądze na niemożność zmierzenia różnicy w rzeczywistym systemie. EnumType.ORDINAL jest w rzeczywistości wartością domyślną, jeśli po prostu wykonasz @Enumerated. Myślę, że większość ludzi (szczególnie DBA) preferuje nazwę wyliczenia w DB.
Gareth Davis,
1
Jak mogę zmienić długość kolumny dla tych wyliczeń? Próbowałem dodać adnotację kolumny, ale to nie jest honorowane?
Kannan Ekanath
2
Musisz zadać to jako kolejne pytanie.
Gareth Davis
2
Użyj ŁAŃCUCHA zamiast ORDINAL, ponieważ umożliwia to dodawanie dodatkowych elementów do Enum niezależnie od kolejności.
Matthew Daumen
14

Z dokumentacji Hibernate: http://www.hibernate.org/272.html

Możesz utworzyć nową definicję typu typedef dla każdego wyliczenia i odwołać się do tych typów w tagu property.

Przykładowe mapowanie - <type>tag wbudowany

  <property name='suit'>
    <type name="EnumUserType">
      <param name="enumClassName">com.company.project.Suit</param>
    </type>
  </property>

Przykładowe mapowanie - użycie <typedef>

  <typedef name="suit" class='EnumUserType'>
      <param name="enumClassName">com.company.project.Suit</param>
  </typedef>

  <class ...>
    <property name='suit' type='suit'/>
  </class>
Craig
źródło
Dzięki. Byłem już świadomy tego rozwiązania. Problem polega na tym, że wymaga, aby wszystkie wyliczenia używały wewnętrznych typów hibernacji, co może powodować problemy, jeśli używasz DAO jako DTO, jak w moim przypadku. Lepsze rozwiązanie opisano tutaj: hibernate.org/273.html
Georgios Gousios
1
Należy zauważyć, że w nowszych wersjach nazwą parametru jest enumClasszamiast enumClassName.
Ryan Ransford