요청은 배열로 여러개의 데이터를 받는데 DB에 배열 요소를 하나씩 저장하기는 비효율적이라 배열을 통째로 컬럼 한개에 저장하고 싶은 상황
- Request : [
A
,B
,C
] => 3개의 데이터를 보냄- DataBase :
1.A
,B
,C
=> 3개를 각각 저장하는 건 X
2.[A, B, C]
=> 통째로 묶어서 1개로 저장 O
Entity와 DB사이에서 속성의 변환을 담당하는 AttributeConverter
를 활용해서 배열을 통째로 문자열로 변환해 저장한다.
convertToEntityAttribute
)의 특정 동작 수행 → 그 결과를 Entity 속성값에 입력convertToDatabaseColumn
)의 특정 동작 수행 → 그 결과를 DB의 컬럼에 저장/* Converter */
public class MyConverter implements AttributeConverter<List<DATATYPE>, String> {
/* DB에 저장될 때 : List<DATATYPE> -> String */
@Override
public String convertToDatabaseColumn(List<DATATYPE> attribute) {
...
}
/* DB에서 조회할 때 : String -> List<DATATYPE> */
@Override
public List<DATATYPE> convertToEntityAttribute(String dbData) {
...
}
}
/* Entity */
public class Assignment {
...
/* 해당 필드 저장/조회에 사용될 Converter 지정 */
@Convert(converter = MyConverter.class)
private List<DATATYPE> arrayData;
}
Long
형 배열을 문자열로 변환해서 저장 & 문자열을 Long
형 배열로 변환해서 조회하는 Converter
/* LongListConverter.java */
import com.fasterxml.jackson.core.type.TypeReference;
public class LongListConverter implements AttributeConverter<List<Long>, String> {
private static final ObjectMapper mapper = new ObjectMapper()
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, false);
@Override
public String convertToDatabaseColumn(List<Long> attribute) {
try {
return mapper.writeValueAsString(attribute);
} catch (JsonProcessingException e) {
throw new IllegalArgumentException();
}
}
@Override
public List<Long> convertToEntityAttribute(String dbData) {
TypeReference<List<Long>> typeReference = new TypeReference<List<Long>>() {};
try {
return mapper.readValue(dbData, typeReference);
} catch (IOException e) {
throw new IllegalArgumentException();
}
}
}
/* Assignment.java */
public class Assignment {
...
@Column(nullable = false)
@Convert(converter = LongListConverter.class)
private List<Long> frequency;
}
➕ 2023.06.17 추가
엔티티->디비 저장은 잘됐는데, 디비->엔티티는 딱히 테스트할 일이 없어서 잘못된 코드를 써놓고도 몰랐다. 이번에 디비에서 해당값을 읽어와서 사용하는데 자꾸 캐스팅 오류가 나서 (Integer는 Long으로 캐스팅할 수 없다는 오류) 코드를 제대로 바꿔줬다.// 이전 mapper.readValue(dbData, List.class); // 현재 TypeReference<List<Long>> typeReference = new TypeReference<List<Long>>() {}; mapper.readValue(dbData, typeReference);
{
...
"frequency" : [2,5]
}
String형 배열도 똑같이 쓰면 된다.
/* StringListConverter.java */
public class StringListConverter implements AttributeConverter<List<String>, String> {
private static final ObjectMapper mapper = new ObjectMapper()
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, false);
@Override
public String convertToDatabaseColumn(List<String> attribute) {
try {
return mapper.writeValueAsString(attribute);
} catch (JsonProcessingException e) {
throw new IllegalArgumentException();
}
}
@Override
public List<String> convertToEntityAttribute(String dbData) {
TypeReference<List<String>> typeReference = new TypeReference<List<String>>() {};
try {
return mapper.readValue(dbData, typeReference);
} catch (IOException e) {
throw new IllegalArgumentException();
}
}
}
/* Submit.java */
public class Submit {
...
@Column(nullable = false, length = 1000)
@Convert(converter = StringListConverter.class)
private List<String> imageUrl;
}
문자열의 경우, 전체 길이가 디폴트값(varchar(255)
)으로 부족해서 length
속성을 활용해 최대 길이를 varchar(1000)
으로 늘려줬다.
💣
ddl-auto = update
로 해놔서 그런지 변경사항이 안먹혀서 테이블을 아예 날리고 새로 만들었다.
요청
DB
[Spring] 테이블의 컬럼 하나에 N개의 값을 넣고 싶다면?
[Java] AttributeConverter를 이용하여 DB에 Entity의 컬렉션 필드 저장하기