7.1 ์ž์‹ ๋งŒ์˜ ์œ ํ˜• ๋ณ€ํ™˜๊ธฐ ๋งŒ๋“ค๊ธฐ

๋•Œ๋•Œ๋กœ ํ…Œ์ด๋ธ”์˜ ํ•œ ์—ด์— ์ƒ๋‹นํžˆ ๋ณต์žกํ•œ ๋ฐ์ดํ„ฐ ์œ ํ˜•์„ ์ €์žฅํ•˜๋ ค๋Š” ๊ฒฝ์šฐ ์ƒํ™ฉ์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. Hibernate๊ฐ€ ๋ฌธ์ž์—ด๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•ˆ๋‹ค๋ฉด ๋ชจ๋“  ๊ฒƒ์ด ์ •์ƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์€ ๊ฒฝ์šฐ ์ž์ฒด ๋ฐ์ดํ„ฐ ๋ณ€ํ™˜๊ธฐ๋ฅผ ์ž‘์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ์‚ฌ์šฉ์ž์˜ ์ƒ๋…„์›”์ผ์„ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๋กœ ์ €์žฅํ•˜๊ธฐ๋กœ ๊ฒฐ์ •ํ–ˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค YY.MM.DD. ์˜ˆ๋ฅผ ๋“ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค 98.12.15. ๋˜ํ•œ ์ผ๋ฐ˜ ๋‚ ์งœ๋กœ ๋ณ€ํ™˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค 15/12/1998. ๊ทธ๋Ÿฐ ๋‹ค์Œ ์ž์‹ ๋งŒ์˜ ๋ณ€ํ™˜๊ธฐ๋ฅผ ์ž‘์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ด๋ ‡๊ฒŒ ํ•˜๋ ค๋ฉด ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค AttributeConverter<EntityType, DbType>.


@Converter(autoApply = true)
public class DateConverter implements AttributeConverter<java.time.LocalDate, String> {
 
    public String convertToDatabaseColumn(java.time.LocalDate date) {
    	return date.format("YY.MM.DD");
    }
 
    public java.time.LocalDate convertToEntityAttribute(String dbData) {
    	String[] data = dbData.split(".");
    	return LocalDate.of(data[2], data[1], "19"+data[0]);
    }
}

๋ฌผ๋ก  ์ด ๋ณ€ํ™˜๊ธฐ๋Š” ๋ชจ๋“  ํ•„๋“œ์— ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(์œ ํ˜•์ด ์ผ์น˜ํ•˜๋Š” ๊ฒฝ์šฐ).


@Entity
@Table(name="user")
class User {
   @Id
   @Column(name="id")
   public Integer id;
 
   @Column(name="join_date")
   @Convert(converter = DateConverter.class)
   public java.time.LocalDate date;
}

๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์„ค๊ณ„ํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ ๋ณ€ํ™˜๊ธฐ๋ฅผ ์ž์ฃผ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ฑฐ๊ธฐ์— ์žˆ๋Š” ๋ฐ์ดํ„ฐ๋Š” "์ด์ƒํ•œ ํ˜•์‹"์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚ ์งœ๋Š” ๋ฌธ์ž์—ด๋กœ, ๋ถ€์šธ์€ Y ๋ฐ N ๊ฐ’์ด ์žˆ๋Š” CHAR ๋“ฑ์œผ๋กœ ์ €์žฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

7.2 ์ž์ฒด ๋ฐ์ดํ„ฐ ์œ ํ˜• ๋งŒ๋“ค๊ธฐ

Hibernate์— ์•Œ๋ ค์ง„ ์œ ํ˜• ๋ชฉ๋ก์ด ์žˆ๋Š” ํ‘œ๋ฅผ ๊ธฐ์–ตํ•˜์‹ญ๋‹ˆ๊นŒ? ์ฃผ์„๊ณผ ํ•จ๊ป˜ ์ง€์ •๋œ ์œ ํ˜•์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค @Type. Hibernate์˜ ๋‹ค๋ฅธ ๋‚ด์žฅ ์œ ํ˜•๊ณผ ๋™์ผํ•œ ๋ฐฉ์‹์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ณ ์œ ํ•œ ๋ฐ์ดํ„ฐ ์œ ํ˜•์„ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— TIME์ด ์•„๋‹ˆ๋ผ VARCHAR๋กœ ์ €์žฅ๋˜๋Š” LocalTime ์œ ํ˜•์„ ์›ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์šฐ๋ฆฌ๋Š” ๊ทธ๋Ÿฌํ•œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์•ก์„ธ์Šคํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ํ•ด๋‹น ์—ด์˜ ๋ฐ์ดํ„ฐ ์œ ํ˜•์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ ์šฐ๋ฆฌ๋Š” ์šฐ๋ฆฌ ์ž์‹ ์˜ Hibernate ์œ ํ˜•์„ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. LocalTimeString์ด๋ผ๊ณ  ๋ถ€๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค.

๋จผ์ € ์ƒˆ ์œ ํ˜•์„ ์„ค๋ช…ํ•˜๋Š” ์ž‘์€ ํด๋ž˜์Šค๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

public class LocalTimeStringType extends AbstractSingleColumnStandardBasicType<<LocalTime> {

    public static final LocalTimeStringType  INSTANCE = new LocalTimeStringType ();

    public LocalTimeStringType () {
    	super(VarcharTypeDescriptor.INSTANCE, LocalTimeStringJavaDescriptor.INSTANCE);
    }

    @Override
    public String getName() {
    	return "LocalTimeString";
    }
}

ํ•˜๋‚˜์˜ ๊ฐ’์œผ๋กœ ๊ตฌ์„ฑ๋œ Enum ์œ ํ˜•์ž…๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋‹จ์ผ enam ์„ธํŠธ๋Š” Hibernate์— ์•Œ๋ ค์ง„ ๋ชจ๋“  ์œ ํ˜•์ž…๋‹ˆ๋‹ค.

๋˜ํ•œ ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์„ ํฌํ•จํ•˜๋Š” ๋ณ€ํ™˜๊ธฐ์˜ ์•„๋‚ ๋กœ๊ทธ ํด๋ž˜์Šค wrap()์™€ unwrap()LocalTime ์œ ํ˜•์˜ ๊ฐ’์„ ๋ฌธ์ž์—ด๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ํด๋ž˜์Šค๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ์€ ๋ฉ”์„œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•˜์ง€ ์•Š๊ณ  ํ‘œ์‹œ๋˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค.

public class LocalTimeStringJavaDescriptor extends AbstractTypeDescriptor<LocalTime> {

    public static final LocalTimeStringJavaDescriptor INSTANCE =  new  LocalTimeStringJavaDescriptor();

    public LocalTimeStringJavaDescriptor() {
    	super(LocalTime.class, ImmutableMutabilityPlan.INSTANCE);
    }

    public <X> X unwrap(LocalTime value, Class<X> type, WrapperOptions options) {

    }

    public <X> LocalTime wrap(X value, WrapperOptions options) {

    }

}

์ด์ œ ๋ฉ”์„œ๋“œ ๊ตฌํ˜„์„ ์ž‘์„ฑํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

public <X> X unwrap(LocalTime value, Class<X> type, WrapperOptions options) {

    if (value == null)
    	return null;

    if (String.class.isAssignableFrom(type))
    	return (X) LocalTimeType.FORMATTER.format(value);

    throw unknownUnwrap(type);
}

๋‘ ๋ฒˆ์งธ ๋ฐฉ๋ฒ•:

@Override
public <X> LocalTime wrap(X value, WrapperOptions options) {
    if (value == null)
    	return null;

    if(String.class.isInstance(value))
    	return LocalTime.from(LocalTimeType.FORMATTER.parse((CharSequence) value));

    throw unknownWrap(value.getClass());
}

์ค€๋น„๊ฐ€ ๋œ. ์ด ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์‹œ๊ฐ„์„ ๋ฌธ์ž์—ด๋กœ ์ €์žฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


@Entity
@Table(name="user")
class User
{
   @Id
   @Column(name="id")
   public Integer id;
 
   @Column(name="join_time")
   @Type(type = "com.codegym.hibernate.customtypes.LocalTimeStringType")  
   public java.time.LocalTime time;
}

7.3 ์œ ํ˜• ๋“ฑ๋ก

Hibernate ๊ตฌ์„ฑ ์ค‘์— ๋ฐ์ดํ„ฐ ์œ ํ˜•์„ ๋“ฑ๋กํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์‚ฌ์†Œํ•œ ์ผ์ด ์•„๋‹™๋‹ˆ๋‹ค.


ServiceRegistry serviceRegistry = StandardServiceRegistryBuilder()
    .applySettings(getProperties()).build();
                                                                                                                                                              	                                        	 
    MetadataSources metadataSources = new MetadataSources(serviceRegistry);
    Metadata metadata = metadataSources
  	.addAnnotatedClass(User.class)
  	.getMetadataBuilder()
  	.applyBasicType(LocalTimeStringType.INSTANCE)
  	.build();
                                                                                                                                                              	                                        	 
    SessionFactory factory =  metadata.buildSessionFactory();

๋จผ์ € MetadataSources๋ฅผ ๊ฐ€์ ธ์™€ MetadataBuilder๋ฅผ ๊ฐ€์ ธ์™€ ํด๋ž˜์Šค๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋ฅผ ํ†ตํ•ด ๊ฐ€๋Šฅ hibernate.cfg.xmlํ•˜์ง€๋งŒ ์กฐ๊ธˆ ๋ฒˆ๊ฑฐ๋กญ๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ๋“ฑ๋ก ํ›„ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


@Entity
@Table(name="user")
class User
{
   @Id
   @Column(name="id")
   public Integer id;
 
   @Column(name="join_time")
   @Type(type = "LocalTimeString")  
   public java.time.LocalTime time;
}