これは以前に尋ねられたことは知っていますが、これまでに見つけた情報に基づいてソリューションを実装することはできませんでした。多分誰かがそれを私に説明できるでしょう。
「ステータス」という表があります。 IDと名前の2つの列があります。 idはPKです。
POJOステータスを使用する代わりに、列挙型を使用したいと思います。このような列挙型を次のように作成しました。
public enum Status {
NEW(1), READY(2), CLOSED(3);
private int id;
public void setId(int id) {
this.id = id;
}
public int getId() {
return this.id;
}
Status(int id) {
this.id = id;
}
}
ここに私のマッパーがあります
<select id="getStatusByName" resultType="Status" parameterType="String">
SELECT ls.id, ls.name
FROM status AS ls
WHERE ls.name = #{name}
</select>
しかし、何らかの理由で、列挙型を取得しようとすると、何かが壊れますが、例外はスローされません。
私はいくつかの角度からこの質問に取り組みました、そしてここに私の発見があります。警告:これらすべての調査はMyBatis-3.1.1を使用して行ったため、以前のバージョンでは動作が異なる可能性がありました。
まず、MyBatisにはEnumTypeHandler
が組み込まれています。デフォルトでは、Java enumを指定すると、これがそのタイプを処理するものになります。クエリの場合、データベースレコードをJava列挙型、EnumTypeHandlerは引数を1つだけ取り、その値に対応するJava enum値を検索しようとします。
例で説明します。上記のクエリが「Ready」を引数として渡すと、2
および"Ready"
が返されるとします。その場合、エラーメッセージNo enum constant com.foo.Status.2
が表示されます。 SELECTステートメントの順序を逆にすると
SELECT ls.name, ls.id
エラーメッセージはNo enum constant com.foo.Status.Ready
です。 MyBatisが何をしているか推測できると思います。 EnumTypeHandlerはクエリから返された2番目の値を無視していることに注意してください。
クエリを
SELECT UPPER(ls.name)
機能させます:Status.READY列挙が返されます。
次に、Status列挙型に独自のTypeHandlerを定義しようとしました。残念ながら、デフォルトのEnumTypeHandler
と同様に、正しいEnumを参照するために、値(idまたはname)の1つだけを取得できました。両方を取得することはできませんでした。したがって、データベースIDが上記でハードコーディングした値と一致しない場合は、不一致になります。データベースIDが常に列挙型で指定したIDと一致することを確認した場合、データベースから必要なのは名前(大文字に変換されたもの)だけです。
次に、私は巧妙になってMyBatis ObjectFactoryを実装し、int idとString名の両方を取得して、Java enumで一致することを確認しますが、うまくいきませんでした。 MyBatisは、Java列挙型のObjectFactoryを呼び出さないため(少なくとも、機能させることができませんでした)。
したがって、私の結論は、Java MyBatisのenumは、データベースの名前をenum定数名に一致させる必要がある限り簡単です-組み込みのEnumTypeHandlerを使用するか、 SQLでUPPER(name)を実行してもJava enum名と一致するのに十分でない場合は所有します。多くの場合、列挙値は単に列と単一の値のみがあり、IDも含まれていません。intIDと名前も一致させる必要がある場合は、Java =列挙型またはデータベースエントリ、あるいはその両方。
最後に、これの実際の例を見たい場合は、MyBatisのkoansのkoan 23を参照してください: https://github.com/midpeter444/mybatis-koans 。私のソリューションを確認するだけの場合は、completed-koans/koan23ディレクトリを確認してください。また、Java列挙型を介してデータベースにレコードを挿入する例もあります。
カスタムTypeHandlerを使用して結果を直接ENUMに変換できるため、データベース内のすべての値を大文字のENUM名として置く必要はありません。
これは、ステータス列挙カスタムハンドラーがどのようになるかです。
public class StatusTypeHandler implements TypeHandler<Status> {
public Status getResult(ResultSet rs, String param) throws SQLException {
return Status.getEnum(rs.getInt(param));
}
public Status getResult(CallableStatement cs, int col) throws SQLException {
return Status.getEnum(cs.getInt(col));
}
public void setParameter(PreparedStatement ps, int paramInt, Status paramType, JdbcType jdbctype)
throws SQLException {
ps.setInt(paramInt, paramType.getId());
}
}
このコードを追加して、mybatis-config.xmlでデフォルトでステータスを処理するようにTypeHandlerを定義します。
<typeHandlers>
<typeHandler javaType='Status' handler='StatusTypeHandler' />
</typeHandlers>
Daoに次の2つの関数がある例を考えてみましょう。
Status getStatusById(int code);
Status getStatusByName(String name);
マッパーは次のようになります
<select id="getStatusById" resultType="Status" parameterType="int">
SELECT ls.id
FROM status AS ls
WHERE ls.id = #{id}
</select>
<select id="getStatusByName" resultType="Status" parameterType="String">
SELECT ls.id
FROM status AS ls
WHERE ls.name = #{name}
</select>
これで、両方のマッパーのresultTypeがStatusであるため、myBatisはこのタイプのCustomTypeHandlerを使用します。つまり、デフォルトでEnumの処理に使用するEnumTypeHandlerの代わりにStatusTypeHandlerを使用するため、データベースで適切なEnum名を維持する必要はありません。