Почему Arraylist сохраняется в базе данных H2 в виде длинной и случайной строки?

#java #sql #spring-boot #kotlin #spring-data-jpa

Вопрос:

Я создал объект (модель или класс данных) в проекте Spring-Boot (Kotlin), который содержит поле с типом Arraylist, но когда я отправляю массив данных в формате JSON из Postman, массив сохраняется в базе данных в виде длинной случайной строки.

Когда я пытаюсь извлечь данные из базы данных, я получаю фактический массив, идеально сформированный.

Мой вопрос в том, почему ArrayList хранится в базе данных H2 таким образом???

Evaluation.kt

 @Entity
data class Evaluation (
 @Id val id : String,
 val timeStamp : Long,
 val symptoms : ArrayList<String>,
 val travelHistory : Boolean,
 val contactWithCovidPatient : Boolean,
 val evaluatedBy : String,
 var evaluationPercentage : String? = null,
 @ManyToOne var user: User? = null
)
 

EvaluationController.kt

 @RestController
class EvaluationController (val evaluationService: IEvaluationService) {

@PostMapping("evaluate/{userId}")
fun evaluateUser(@PathVariable userId : String, @RequestBody evaluation: Evaluation) : ResponseEntity<Evaluation> =
    ResponseEntity.ok().body(evaluationService.addEvaluation(evaluation, userId))

}
 

Тело запроса JSON

 {
"id":"e_01",
"timeStamp":"123456789",
"pinCode":"123457",
"travelHistory":true,
"contactWithCovidPatient":true,
"evaluatedBy":"u_01",
"symptoms": ["Fever","Cough"]
}
 

Ответ JSON

 {
"id": "e_01",
"timeStamp": 123456789,
"symptoms": [
    "Fever",
    "Cough"
],
"travelHistory": true,
"contactWithCovidPatient": true,
"evaluatedBy": "u_01",
"evaluationPercentage": "95",
"user": {
    "id": "u_01",
    "name": "abc01",
    "phoneNumber": "9876543210",
    "pinCode": "123457",
    "covidResult": "Positive"
}
}
 

Таблица базы данных H2

введите описание изображения здесь

Ответ №1:

Это шестнадцатеричная строка, представляющая сериализованный ArrayList объект. Подробнее о сериализации объектов в Java см. В разделе Сериализуемые объекты.

Выполнение следующего кода дает тот же результат:

 List<String> symptoms = new ArrayList<>(Arrays.asList("Fever", "Cough"));
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(symptoms);
byte[] serializedObject = byteArrayOutputStream.toByteArray();
String hex = Hex.encodeHexString(serializedObject); // Apache Commons Codec
System.out.println(hex);
 
 aced0005737200136a6176612e7574696c2e41727261794c6973747881d21d99c7619d03000149000473697a657870000000027704000000027400054665766572740005436f75676878
 

Комментарии:

1. есть ли какой-либо способ сохранить обычный массив в базе данных??

2. Обычно вы используете @ElementCollection . В этом случае элементы коллекции хранятся в отдельной таблице.

Ответ №2:

Необработанная строка, отображаемая в БД, является сериализованным объектом.

Один из способов реализации этого — сначала объединить ваш string ArrayList в одну строку с разделителями, но я настоятельно не рекомендую этого делать. В общем, это плохая практика — помещать список в одно поле таблицы. Что вам следует сделать, так это создать отдельную таблицу для симптомов с отношением «один ко многим» с оценкой.

Вы должны знать о денормализации при проектировании своих объектов при использовании JPA. В вашем случае рассмотрите следующие вопросы :

  1. Что произойдет, если вы захотите запросить оценки с определенными симптомами?
  2. Что произойдет, если вы захотите запросить список всех симптомов?
  3. Что произойдет, если вы захотите расширить симптомы с помощью какой-либо другой детали, например, даты появления симптома?

Если вы когда-либо пытались добавить коллекцию чего-либо в поле базы данных, в 99,9999% случаев вы делаете это неправильно. Симптомы должны быть их собственной сущностью, и у вас есть отношение «один ко многим» или «многие ко многим» между оценкой и симптомом, в зависимости от того, что вам требуется.

Редактировать :

Чтобы уточнить мой ответ дальше, при разработке классов объектов подумайте о том, является ли поле объектом значения или сущностью. Объект значения — это то, что не может быть разбито дальше и может быть представлено примитивом, таким как Date, String, Int и т.д. Некоторыми примерами могут быть идентификатор объекта, имя, номер телефона и т.д.

Сущность — это объект, который можно расширить, например, созданный вами объект оценки. В оценках у вас есть список симптомов, и вы рассматриваете симптомы как объект значения. Является ли это объектом значения? Я могу сразу подумать о некоторых дополнительных полях, которые вы могли бы поместить в объект симптомов, и, денормализуя симптомы так, как вы это сделали, вы также вводите тонны повторяющихся данных в базу данных.

Объект оценки, содержащий [«Лихорадка», «Кашель»] в вашей реализации, будет введен в базу данных как одно поле. Но другой объект оценки, содержащий те же симптомы, будет введен в базу данных для этой оценки, потому что у вас нет зависимости от внешнего ключа или отдельной таблицы, представляющей симптомы. Помимо невозможности запрашивать симптомы в связи с оценками или невозможности запрашивать симптомы самостоятельно.