3

職場のプロジェクトに MyBatis を実装しようとしています。これは、バニラ JDBC を使用してストアド プロシージャのみを介してデータベースにアクセスするレガシー システムです。ストアド プロシージャを呼び出すには、ストアド プロシージャの入力パラメータを含むオブジェクトと、結果セットを保持する別のオブジェクトが MyBatis に必要であることを理解しています。これが完全に真実かどうかはわかりません。

システム内にデータ エンティティを作成しすぎないようにするために、既存のものを再利用したいと考えています。そして、ここで問題が発生します。私が直面している典型的な状況/シナリオと、それをどのように解決しようとしているのかを説明させてください.

システムに次のデータ エンティティがあるとします。

class Account {
    private int accountID;
    private String accountName;
    private OrganizationAddress address;
    // Getters-Setters Go Here
}
class OrganizationAddress extends Address {
    // ... some attributes here
    // Getters-Setters Go Here
}
class Address {
    private String address;
    private String city;
    private String state;
    private String country;
    // Getters-Setters Go Here
}

私は注釈を使用しているので、私のMapperクラスには次のようなものがあります:

@Select(value = "{call Get_AccountList(#{accountType, mode=IN, jdbcType=String})}")
@Options(statementType = StatementType.CALLABLE)
@Results(value = {
    @org.apache.ibatis.annotations.Result
        (property = "accountID", column = "Account_ID"),
    @org.apache.ibatis.annotations.Result
        (property = "accountName", column = "Organization_Name"),
    @org.apache.ibatis.annotations.Result
        (property = "state", column = "State", javaType=OrganizationAddress.class)
    })
List<Account> getAccountList(Param param);

問題:ストアド プロシージャを呼び出すと、Accountオブジェクトにはstatealwaysがありますnull

怪我に加えて、私は上記のデータ エンティティのソースにアクセスできません。そのため、このリンクで提供されているソリューションも試すことができませんでした-Mybatisはネストされたオブジェクトで選択します

私のクエリ:

  • システムに既に存在するデータ エンティティを使用することは可能ですか? それとも、新しいデータ エンティティを作成してから、データを既存のものにマップする必要がありますか?
    • はいの場合、どうすればいいですか?参考文献があれば。
    • いいえの場合、ストアド プロシージャを呼び出すために作成するデータ エンティティの数を減らす方法はありますか (in パラメータと out パラメータの両方に対して)。
4

1 に答える 1

5

あなたの状況に対する最善の解決策は (私が正しく理解していれば)、状態列を OrganizationAddress オブジェクトにマップする MyBatis TypeHandler を使用することだと思います。

あなたが提供した情報に基づいて例をまとめましたが、それは機能します。改訂された注釈付きマッパーは次のとおりです。

// Note: you have an error in the @Select line => maps to VARCHAR not "String"
@Select(value = "{call Get_AccountList(#{accountType, mode=IN, jdbcType=VARCHAR})}")
@Options(statementType = StatementType.CALLABLE)
@Results(value = {
  @org.apache.ibatis.annotations.Result
      (property = "accountID", column = "Account_ID"),
  @org.apache.ibatis.annotations.Result
      (property = "accountName", column = "Organization_Name"),
  @org.apache.ibatis.annotations.Result
      (property = "address", column = "State", typeHandler=OrgAddressTypeHandler.class)
  })
List<Account> getAccountList(Param param);

Account の address フィールドを「state」列にマップし、TypeHandler を使用して「state」プロパティが入力された OrganizationAddress を作成する必要があります。

私が作成した OrgAddressTypeHandler は次のようになります。

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;

public class OrgAddressTypeHandler extends BaseTypeHandler<OrganizationAddress> {

  @Override
  public OrganizationAddress getNullableResult(ResultSet rs, String colName) throws SQLException {
    OrganizationAddress oa = new OrganizationAddress();
    oa.setState(rs.getString(colName));
    return oa;
  }

  @Override
  public OrganizationAddress getNullableResult(ResultSet rs, int colNum) throws SQLException {
    OrganizationAddress oa = new OrganizationAddress();
    oa.setState(rs.getString(colNum));
    return oa;
  }

  @Override
  public OrganizationAddress getNullableResult(CallableStatement cs, int colNum) throws SQLException {
    OrganizationAddress oa = new OrganizationAddress();
    oa.setState(cs.getString(colNum));
    return oa;
  }

  @Override
  public void setNonNullParameter(PreparedStatement arg0, int arg1, OrganizationAddress arg2, JdbcType arg3) throws SQLException {
    // not needed for this example
  }
} 

これよりも完全な動作例が必要な場合は、喜んでさらにお送りします。または、あなたの例を誤解している場合は、お知らせください。

このソリューションを使用すると、ドメイン オブジェクトを変更せずに使用できます。マッピングを行うには TypeHandler が必要なだけで、XML マッパー ファイルは必要ありません。

また、MySQL の MyBatis-3.1.1 でこれを行いました。これをテストするために作成した単純なスキーマとストアド プロシージャを次に示します。

DROP TABLE IF EXISTS account;
DROP TABLE IF EXISTS organization_address;

CREATE TABLE account (
  account_id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
  organization_name VARCHAR(45) NOT NULL,
  account_type VARCHAR(10) NOT NULL,
  organization_address_id SMALLINT UNSIGNED NOT NULL,
  PRIMARY KEY  (account_id)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE organization_address (
  organization_address_id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
  address VARCHAR(45) NOT NULL,
  city VARCHAR(45) NOT NULL,
  state VARCHAR(45) NOT NULL,
  country VARCHAR(45) NOT NULL,
  PRIMARY KEY  (organization_address_id)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO organization_address VALUES(1, '123 Foo St.', 'Foo City', 'Texas', 'USA');
INSERT INTO organization_address VALUES(2, '456 Bar St.', 'Bar City', 'Arizona', 'USA');
INSERT INTO organization_address VALUES(3, '789 Quux Ave.', 'Quux City', 'New Mexico', 'USA');

INSERT INTO account VALUES(1, 'Foo',  'Type1', 1);
INSERT INTO account VALUES(2, 'Bar',  'Type1', 2);
INSERT INTO account VALUES(3, 'Quux', 'Type2', 3);

DROP PROCEDURE IF EXISTS Get_AccountList;

DELIMITER $$

CREATE PROCEDURE Get_AccountList(IN p_account_type VARCHAR(10))
READS SQL DATA
BEGIN
     SELECT a.account_id, a.organization_name, o.state
     FROM account a
     JOIN organization_address o ON a.organization_address_id = o.organization_address_id
     WHERE account_type = p_account_type
     ORDER BY a.account_id;
END $$

DELIMITER ;
于 2012-06-23T00:41:24.183 に答える