Domaでvarcharとnvarcharを使い分けたい場合

ちょっとトリッキーな方法ですが、ドメインクラスを使うとできます。まずは利用イメージを示します。

エンティティはこんな感じで、varcharをString、nvarcharをNStringにマッピングするものとします。NStringはもちろんこれから自作するクラスです。

@Entity
public class Person {
  public String name;
  public NString name2;
}

NStringはStringと相互に変換可能で、こんな風に使えます。

Person person = new Person();
person.name2 = NString.of("あいう");
String name2AsString = person.name2.getValue();

使うのはたぶん難しくない。



で、ここからが本題の実現方法の説明です。まずはnvarcharにマッピングするNStringクラスを作ります。DomainアノテーションのvalueType要素には、アプリの他の箇所で使わない型を指定するのがポイント。この例ではjava.sql.Arrayを使います。この例のArrayに相当する型は単なるダミーです。Stringと相互変換できて他の箇所で使っていなければなんでもOKです。

@Domain(valueType = Array.class, accessorMethod = "getAsArray")
public class NString {

    private final ArrayImpl value;

    // package private
    NString(Array value) {
        this.value = (ArrayImpl) value;
    }

    // package private
    Array getAsArray() {
        return this.value;
    }

    public String getValue() {
        return value.getValue();
    }

    public static NString of(String value) {
        return new NString(new ArrayImpl(value));
    }

    public static class ArrayImpl implements Array {

        private final String value;

        public ArrayImpl(String value) {
            this.value = value;
        }

        public String getValue() {
            return value;
        }

        // ログ出力で呼び出される
        @Override
        public String toString() {
            return value;
        }
        // あとはArrayの実装メソッドがつづく、どれも呼び出さないので適当に例外をスローしておいてください
        ...
    }
}

次に使いたいDB(この例ではSQL Server 2008)のDialectに対応するJdbcMappingVisitorを継承して次のように記述します。何をしているかというと、ダミーのArrayとStringの相互変換。それから、JdbcTypes.NSTRINGを使ってStringとnvarcharの相互変換ができるようにしています。

public class MyJdbcMappingVisitor extends Mssql2008JdbcMappingVisitor {

    @Override
    public Void visitArrayWrapper(ArrayWrapper wrapper, JdbcMappingFunction p)
            throws SQLException {
        StringWrapper stringWrapper = new StringWrapper();
        ArrayImpl array = (ArrayImpl) wrapper.get();
        if (array != null) {
            stringWrapper.set(array.getValue());
        }
        p.apply(stringWrapper, JdbcTypes.NSTRING);
        wrapper.set(new ArrayImpl(stringWrapper.get()));
        return null;
    }
}

最後に、ConfigクラスのDialectの設定の際、コンストラクタで上記のJdbcMappingVisitorのインスタンスを渡します。

    private static final Dialect dialect = new Mssql2008Dialect(new MyJdbcMappingVisitor());

ログ出力もカスタマイズしたいということであれば同じ要領でSqlLogFormattingVisitorを継承して出力を調整できます。