Ibatis / MyBatis выбираются динамически без необходимости создания каких-либо Pojo / Mapper - PullRequest
5 голосов
/ 05 июля 2011

Есть ли способ динамически выбирать / обновлять / удалять, используя Ibatis / MyBatis?

Когда я говорю «динамически», это означает, что я вообще не хочу создавать POJO / DataMapper.

Будет приветствоваться любой пример URL.

Ответы [ 3 ]

8 голосов
/ 05 июля 2011

Да, просто установите атрибут resultType на map, и данные таблицы будут помещены в HashMap имен столбцов для значений. Если запрос возвращает более 1 строки, сопоставленные строки будут помещены в список. Если вы хотите выбрать один столбец, вы можете получить только это значение (например, String, int и т. Д.) Или в виде списка.

<select id="test1" resultType="map">select * from user</select>
<select id="test2" resultType="map" parameterType="int">
  select * from user where id=#{value}</select>
<select id="test3" resultType="string">select name from user</select>
...
// returns a list of maps
List test = sqlSession.selectList("test1");

// returns a single map
Object map = sqlSession.selectOne("test2", 0);

// returns a list of strings
List names = sqlSession.selectList("test3");

Это относится к MyBatis 3; Я думаю, что вы можете сделать что-то подобное в iBatis 2.

2 голосов
/ 12 апреля 2017

Следующий подход может быть полезен.Скажем, у вас есть некоторый универсальный интерфейс выбора, например:

public interface IAutoRepository {
    /**
     * The automatically generated insertPKs sql statements.
     * Parts of the query can be set manually in the sql (insert-select query).
     *
     * @param items     the {@link WhereStmt} statements
     * @return the inserted rows count
     */
    @Transactional
    <T extends WhereStmt> Integer insertPKs(@Param("items") List<T> items);

    /**
     * Returns the value based on the {@link Parameter} class
     *
     * @param param     the {@link Parameter} instance
     * @return the searched value in a {@link java.util.Map} form
     */
    @MapKey("VAL")
    <T extends Parameter> Map<String, Map<String, ?>> getDistinctValues(@Param("param") T param);
}

В соответствии с некоторым внешним типом (скажем, один столбец или диапазон дат или диапазон вообще) вы можете определить следующий запрос в шаблоне Common.xml:

<sql id="includeDistinctValues">
SELECT
    <choose>
        <when test='param.type.name() == "set"'>
            DISTINCT ${param.column} AS val
        </when>
        <when test='param.type.name() == "date" or param.type.name() == "range"'>
            <some uid>              AS val,
            MIN(${param.minColumn}) AS min,
            MAX(${param.maxColumn}) AS max
        </when>
    </choose>
FROM ${entityTable}
</sql>

То, что вы получаете от mybatis, - это java.util.Map.Затем вы можете использовать его как-то вроде:

public enum StmtType {
    set((valMap) -> {
        final Set<String> distinctValues = valMap
                .values()
                .stream()
                .map(val -> (String) val.get("VAL"))
                //use in date/range case
                //final Date minDate = (Date) val.get("MIN");
                //final Date maxDate = (Date) val.get("MAX");
                .collect(Collectors.toSet());
        return distinctValues;
    },
            (values, params) -> {
                final SetParameter parameter = (SetParameter) params.getParams();
                return new WhereSetStmt<>(parameter.getColumn(), values, params.getIncludeEmptyValues());
            });
    @Getter
    private Function<Map<String, Map<String, ?>>, ? extends Iterable> toValue;
    @Getter
    private BiFunction<Collection, DataParam, ? extends WhereStmt> toWhereStmt;

    StmtType(
            Function<Map<String, Map<String, ?>>, ? extends Iterable> toValue,
            BiFunction<Collection, DataParam, ? extends WhereStmt> toWhereStmt
    ) {
        this.toValue = toValue;
        this.toWhereStmt = toWhereStmt;
    }
}

, где SetParameter может быть представлен следующим образом:

@Getter
public class SetParameter extends Parameter {
    /**
     * Column in sql query,
     */
    private final String column;
    public SetParameter(String column) {
        super(StmtType.set);
        this.column = column;
    }
}

Более того, вы можете определить некоторые WhereStmt как:

public abstract class WhereStmt {
    /**
     * Type of the statement
     */
    private final StmtType type;
    /**
     * Shall empty values be included.
     */
    private final boolean includeEmptyValues;
}

@Getter
public class WhereSetStmt<T> extends WhereStmt {
    /**
     * The column for `column` IN (...) statement
     */
    private String column;
    /**
     * Values for `column` IN (...) statement
     */
    private Collection<T> values;

    public WhereSetStmt(String column, Collection<T> values, boolean includeEmptyValues) {
        super(StmtType.set, includeEmptyValues);
        this.column = column;
        this.values = values;
    }
}

@Getter
@AllArgsConstructor
public final class DataParam<P extends Parameter> {
    /**
     * Whether to include nullable values.
     */
    private final Boolean includeEmptyValues;
    /**
     * Represents database required information for later processing and sql statements generation.
     */
    private final P params;
}

Наконец, в mybatis generic Common.xml вы можете использовать его следующим образом:

<sql id="includeInsertPkSelect">
    SELECT DISTINCT(${id})
    FROM ${entityTable}
</sql>

<sql id="includeInsertPkWhere">
    <if test="items != null and items.size() > 0">
        AND
        <foreach collection="items" item="item" index="i" separator="AND">
            <choose>
                <when test='item.type.name() == "set" and ( item.values != null and item.values.size() > 0 or item.includeEmptyValues )'>
                    (
                    <if test="item.values != null and item.values.size() > 0">
                        ${item.column} IN
                        <foreach item="value" collection="item.values" separator="," open="("
                                 close=")">
                            #{value}
                        </foreach>
                        <if test="item.includeEmptyValues">
                            OR
                        </if>
                    </if>
                    <if test="item.includeEmptyValues">
                        ${item.column} IS null
                    </if>
                    )
                </when>

                <when test='item.type.name() == "date"'>
                    (
                    COALESCE(${item.column}, SYSDATE + 1000000)
                    BETWEEN #{item.from} AND #{item.to}
                    <if test="item.includeEmptyValues">
                        OR ${item.column} IS NULL
                    </if>
                    )
                </when>
                <when test='item.type.name() == "range"'>
                    (
                    COALESCE(${item.column}, 1000000000)
                    BETWEEN #{item.from} AND #{item.to}
                    <if test="item.includeEmptyValues">
                        OR ${item.column} IS NULL
                    </if>
                    )
                </when>
            </choose>
        </foreach>
    </if>
</sql>

И объединять операторы SQL в качестве шаблона, например:

<insert id='insertPKs'>
    INSERT INTO requiredTable
    <include refid="Common.includeInsertPkSelect">
        <property name="id" value="entityId"/>
        <property name="entityTable" value="entityTable"/>
    </include>
    <include refid="Common.includeInsertPkWhere">
        <property name="id" value="entityId"/>
        <property name="entityTable" value="entityTable"/>
    </include>
</insert>
0 голосов
/ 05 июля 2011

Да, должно быть возможно построить отображение во время выполнения через API и использовать Карты вместо классов сущностей.

...