7.1 独自の型コンバータの作成

かなり複雑なデータ型をテーブルの 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";
    }
}

これは、1 つの値で構成される Enum 型のものです。このような単一の enam のセットは、Hibernate に知られているすべてのタイプです。

また、LocalTime 型の値を String に変換するためのwrap()クラス(2 つのメソッドを含むコンバーターの類似物) も必要です。unwrap()

メソッドを実装しない場合は次のようになります。

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);
}

そして 2 番目の方法:

@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;
}