2012-06-22 4 views
2

Я пытаюсь реализовать MyBatis в моем проекте на работе. Это устаревшая система, которая использует ванильный JDBC для доступа к базе данных, исключительно посредством хранимых процедур. Я понимаю, что для вызова хранимой процедуры MyBatis требует объект, который содержит входные параметры для хранимой процедуры, а другой - для хранения набора результатов. Не уверен, что это полностью верно.Сопоставление результата с SP на сложный объект

Чтобы предотвратить создание слишком большого количества объектов данных в системе, я хочу повторно использовать существующие. И здесь возникает проблема. Позвольте мне объяснить, какова типичная ситуация/сценарий, с которым я столкнулся, и затем, как я пытаюсь ее решить.

Допустим, у меня есть следующий объект данных (е) в системе:

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 имеет state всегда null.

Чтобы добавить к травме, у меня нет доступа к источнику данных объектов данных. Так что я не мог бы попробовать предлагаемое решение по этой ссылке либо - Mybatis select with nested objects

Мой запрос:

  • Можно ли мне использовать entites данных, которые уже присутствуют в системе, или же я должен создать новые, а затем сопоставить данные с существующими?
    • Если да, то как это сделать? Любые ссылки, если они есть.
    • Если нет, существует ли способ уменьшить количество объектов данных, которые я создавал бы для вызова хранимых процедур (для обоих параметров ввода и вывода)?

ответ

3

Я думаю, что лучшее решение для вашей ситуации (если я правильно понимаю) заключается в использовании MyBatis TypeHandler, который будет отображать государственный столбец объект OrganizationAddress.

Я собрал пример, основанный на предоставленной вами информации, и он работает. Вот пересмотренный аннотированный Mapper:.

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

Вам нужно отобразить поле адреса учетной записи в графу «состояние» и использовать TypeHandler создать 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.

Также я сделал это с MyBatis-3.1.1 в MySQL. Вот простая схема и хранимая процедура, которую я создал для ее проверки:

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 ; 
+0

Да, вы правильно поняли мою проблему, и это решение работает для меня. Спасибо! :) – Rishabh

Смежные вопросы