Мы никогда перечисления хранилища как числовые порядковые номера больше; это делает отладку и поддержку слишком трудными. Мы храним фактическую перечислимую величину, преобразованную в строку:
public enum Suit { Spade, Heart, Diamond, Club }
Suit theSuit = Suit.Heart;
szQuery = "INSERT INTO Customers (Name, Suit) " +
"VALUES ('Ian Boyd', %s)".format(theSuit.name());
и затем читают назад с:
Suit theSuit = Suit.valueOf(reader["Suit"]);
проблема была в прошлом, уставившись на Руководителя предприятия и пытаясь дешифровать:
Name Suit
================== ==========
Shelby Jackson 2
Ian Boyd 1
стихи
Name Suit
================== ==========
Shelby Jackson Diamond
Ian Boyd Heart
последний намного легче. Первый потребовал достигания исходного кода и нахождения численных значений, которые были присвоены участникам перечисления.
Да это занимает больше места, но имена элемента перечисления коротки, и жесткие диски являются дешевыми, и это намного больше стоит того для помощи, когда у Вас есть проблема.
Кроме того, при использовании численных значений Вы связываетесь с ними. Вы не можете приятно ввести или перестроить участников, не имея необходимость вызывать старые численные значения. Например, изменяя перечисление Иска на:
public enum Suit { Unknown, Heart, Club, Diamond, Spade }
должен был бы стать:
public enum Suit {
Unknown = 4,
Heart = 1,
Club = 3,
Diamond = 2,
Spade = 0 }
для поддержания численных значений прежней версии, сохраненных в базе данных.
, вопрос подходит: позволяет говорят, что я хотел заказать значения. Некоторые люди могут хотеть отсортировать их по порядковому номеру перечисления. Конечно, упорядочивание карт численным значением перечисления бессмысленно:
SELECT Suit FROM Cards
ORDER BY SuitID; --where SuitID is integer value(4,1,3,2,0)
Suit
------
Spade
Heart
Diamond
Club
Unknown
Это не порядок, который мы хотим - мы хотим их в порядке перечисления:
SELECT Suit FROM Cards
ORDER BY CASE SuitID OF
WHEN 4 THEN 0 --Unknown first
WHEN 1 THEN 1 --Heart
WHEN 3 THEN 2 --Club
WHEN 2 THEN 3 --Diamond
WHEN 0 THEN 4 --Spade
ELSE 999 END
та же работа, которая требуется при сохранении целочисленных значений требуется при сохранении строк:
SELECT Suit FROM Cards
ORDER BY Suit; --where Suit is an enum name
Suit
-------
Club
Diamond
Heart
Spade
Unknown
, Но это не порядок, который мы хотим - мы хотим их в порядке перечисления:
SELECT Suit FROM Cards
ORDER BY CASE Suit OF
WHEN 'Unknown' THEN 0
WHEN 'Heart' THEN 1
WHEN 'Club' THEN 2
WHEN 'Diamond' THEN 3
WHEN 'Space' THEN 4
ELSE 999 END
Мое мнение - то, что этот вид рейтинга принадлежит пользовательского интерфейса. Если Вы - элементы сортировки на основе их перечислимой величины: Вы делаете что-то не так.
, Но если бы Вы хотели действительно сделать это, я создал бы Suits
таблица измерений:
| Suit | SuitID | Rank | Color |
|------------|--------------|---------------|--------|
| Unknown | 4 | 0 | NULL |
| Heart | 1 | 1 | Red |
| Club | 3 | 2 | Black |
| Diamond | 2 | 3 | Red |
| Spade | 0 | 4 | Black |
Таким образом, когда Вы хотите изменить свои карты для использования Целующиеся Короли Новый Порядок Деки, можно изменить его в целях дисплея, не выбрасывая все данные:
| Suit | SuitID | Rank | Color | CardOrder |
|------------|--------------|---------------|--------|-----------|
| Unknown | 4 | 0 | NULL | NULL |
| Spade | 0 | 1 | Black | 1 |
| Diamond | 2 | 2 | Red | 1 |
| Club | 3 | 3 | Black | -1 |
| Heart | 1 | 4 | Red | -1 |
Теперь мы разделяем внутреннюю деталь программирования (имя перечисления, перечислимая величина) с установкой дисплея, предназначенной для пользователей:
SELECT Cards.Suit
FROM Cards
INNER JOIN Suits ON Cards.Suit = Suits.Suit
ORDER BY Suits.Rank,
Card.Rank*Suits.CardOrder
Если у Вас нет причин реального исполнения избежать его, я рекомендовал бы использовать отдельную таблицу для перечисления. Используйте целостность внешнего ключа, если дополнительный поиск действительно не уничтожает Вас.
suit_id suit_name
1 Clubs
2 Hearts
3 Spades
4 Diamonds
player_name suit_id
Ian Boyd 4
Shelby Lake 2
suit_id
) независимы от Вашей перечислимой величины, которая помогает Вам работать над данными из других языков также. Я утверждал бы, что единственный безопасный механизм здесь должен использовать Строку name()
значение. При записи в DB Вы могли использовать sproc, чтобы вставить значение и при чтении, использовать Представление. Этим способом, если перечисления изменяются, существует уровень абстракции в sproc/view, чтобы быть в состоянии представить данные как перечисление значений, не "налагая" это на DB.
Как Вы говорите, порядковый немного опасно. Рассмотрите, например:
public enum Boolean {
TRUE, FALSE
}
public class BooleanTest {
@Test
public void testEnum() {
assertEquals(0, Boolean.TRUE.ordinal());
assertEquals(1, Boolean.FALSE.ordinal());
}
}
при хранении этого как ординалов у Вас могли бы быть строки как:
> SELECT STATEMENT, TRUTH FROM CALL_MY_BLUFF
"Alice is a boy" 1
"Graham is a boy" 0
, Но что происходит, если Вы обновили булевскую переменную?
public enum Boolean {
TRUE, FILE_NOT_FOUND, FALSE
}
Это означает, что вся Ваша ложь станет неправильно истолкованной как 'file-not-found'
Лучше, чтобы просто использовать строковое представление
Мы просто храним само перечислимое имя - это более читаемо.
Мы действительно бездельничали с хранением определенных значений для перечислений, где существует ограниченный набор значений, например, это перечисление, которое имеет ограниченный набор состояний, которые мы используем символ для представления (более значимый, чем числовое значение):
public enum EmailStatus {
EMAIL_NEW('N'), EMAIL_SENT('S'), EMAIL_FAILED('F'), EMAIL_SKIPPED('K'), UNDEFINED('-');
private char dbChar = '-';
EmailStatus(char statusChar) {
this.dbChar = statusChar;
}
public char statusChar() {
return dbChar;
}
public static EmailStatus getFromStatusChar(char statusChar) {
switch (statusChar) {
case 'N':
return EMAIL_NEW;
case 'S':
return EMAIL_SENT;
case 'F':
return EMAIL_FAILED;
case 'K':
return EMAIL_SKIPPED;
default:
return UNDEFINED;
}
}
}
и когда у Вас есть много значений, у Вас должна быть Карта в Вашем перечислении для хранения этого getFromXYZ методом маленький.
Для большой базы данных я отказываюсь потерять размер и преимущества скорости числового представления. Я часто заканчиваю с таблицей базы данных, представляющей Перечисление.
можно осуществить непротиворечивость базы данных путем объявления внешнего ключа - хотя в некоторых случаях могло бы быть лучше не объявить, что как ограничение внешнего ключа, которое налагает стоимость на каждую транзакцию. Можно гарантировать непротиворечивость путем периодического выполнения проверки, во времена выбора, с:
SELECT reftable.* FROM reftable
LEFT JOIN enumtable ON reftable.enum_ref_id = enumtable.enum_id
WHERE enumtable.enum_id IS NULL;
другая половина этого решения должна записать некоторый тестовый код, который проверяет, что перечисление Java и таблица перечисления базы данных имеют то же содержание. Это оставляют как осуществление для читателя.
При сохранении перечислений как строк в базе данных можно создать служебные методы для (de), сериализируют любое перечисление:
public static String getSerializedForm(Enum<?> enumVal) {
String name = enumVal.name();
// possibly quote value?
return name;
}
public static <E extends Enum<E>> E deserialize(Class<E> enumType, String dbVal) {
// possibly handle unknown values, below throws IllegalArgEx
return Enum.valueOf(enumType, dbVal.trim());
}
// Sample use:
String dbVal = getSerializedForm(Suit.SPADE);
// save dbVal to db in larger insert/update ...
Suit suit = deserialize(Suit.class, dbVal);