MyBatis、Select Provider 和 SQLBuilder

Fjo*_*rdo 3 java postgresql mybatis mybatis-generator

这不仅仅是一个简单的问题,而且我的英语没有我想要的那么好......我会尽力而为。

\n\n

我使用 java 8,在 Postgres 9.6 上使用 Mybatis 3.4.6,我需要执行自定义动态查询。

\n\n

在我的 mapper.java 类中,我创建了一个与myBatis SQL Builder 类一起使用的方法

\n\n
@SelectProvider(type = PreIngestManager.class, method = "selectPreIngestsSQLBuilder")\n@Results({ @Result(property = "id", column = "id"), @Result(property = "inputPath", column = "input_path"),\n        @Result(property = "idCategoriaDocumentale", column = "id_categoria_documentale"), @Result(property = "idCliente", column = "id_cliente"),\n        @Result(property = "outputSipPath", column = "output_sip_path"), @Result(property = "esito", column = "esito"),\n        @Result(property = "stato", column = "stato"), @Result(property = "pathRdp", column = "path_rdp"),\n        @Result(property = "dataInizio", column = "data_inizio"), @Result(property = "dataFine", column = "data_fine") })\nList<PreIngest> selectPreIngestsByFilters(@Param("idCatDoc") Long idCatDoc, @Param("nomePacchetto") String nomePacchetto,\n        @Param("dataInizioInferiore") Date dataInizioInferiore, @Param("dataInizioSuperiore") Date dataInizioSuperiore,\n        @Param("statiPreIngest") String statiPreIngest);\n
Run Code Online (Sandbox Code Playgroud)\n\n

我已经指定了 @SelectProvider 注释、类和方法来指向,在示例中是 PreIngestManager.class 和 selectPreIngestsSQLBuilder 方法。

\n\n

这是方法

\n\n
public String selectPreIngestsSQLBuilder(Map<String, Object> params) {\n    return new SQL() {\n        {\n            SELECT("*");\n            FROM("pre_ingest");\n            WHERE("id_categoria_documentale = #{idCatDoc}");\n            if (params.get("nomePacchetto") != null)\n                WHERE("input_path like \'%\' || #{nomePacchetto}");\n            if (params.get("dataInizioInferiore") != null) {\n                if (params.get("dataInizioSuperiore") != null) {\n                    WHERE("data_inizio between #{dataInizioInferiore} and #{dataInizioSuperiore}");\n                } else {\n                    WHERE("data_inizio >= #{dataInizioInferiore}");\n                }\n            } else {\n                if (params.get("dataInizioSuperiore") != null) {\n                    WHERE("data_inizio <= #{dataInizioSuperiore}");\n                }\n            }\n            if (params.get("statiPreIngest") != null)\n                WHERE("stato in (#{statiPreIngest})");\n            ORDER_BY("id ASC");\n        }\n    }.toString();\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

这些是我的问题:

\n\n

我必须指定 @Results 注释和每个 @Result ,还是可以使用 java 模型类?我尝试过 @ResultMap(value = { "mycompany.model.PreIngest" }) 但它不起作用。

\n\n

最重要的是,正如文档中所述,使用 SQL 构建器,您可以访问将它们作为最终对象的方法参数

\n\n
// With conditionals (note the final parameters, required for the anonymous inner class to access them)\npublic String selectPersonLike(final String id, final String firstName, \nfinal String lastName) {\nreturn new SQL() {{\n   SELECT("P.ID, P.USERNAME, P.PASSWORD, P.FIRST_NAME, P.LAST_NAME");\n    FROM("PERSON P");\n    if (id != null) {\n      WHERE("P.ID like #{id}");\n    }\n    if (firstName != null) {\n      WHERE("P.FIRST_NAME like #{firstName}");\n    }\n    if (lastName != null) {\n      WHERE("P.LAST_NAME like #{lastName}");\n    }\n    ORDER_BY("P.LAST_NAME");\n    }}.toString();\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

但是,如果我将这些放在我的方法中,我将无法访问它们。我需要从方法声明中删除@Param吗?是否需要在没有 @SelectProvider 的情况下调用 SQLBuilder ?我正在混合溶液吗?

\n\n

据我研究,目前我看到 3 种方法来执行动态查询或自定义 where 条件。

\n\n
    \n
  1. 使用 MyBatisGenerator 库并结合 where 条件作为搜索条件与 SelectByExample 方法一起使用。(当查询很简单时我使用这个)
  2. \n
  3. 直接编写 SQL 查询,使用 if、choose、语句等修改 XML 映射器文件,如下所述
  4. \n
  5. 使用带有 @SelectProvider 注释的SQL Builder 类。
  6. \n
\n\n

您知道什么时候更喜欢 2\xc2\xb0 方法而不是 3\xc2\xb0 方法吗?为什么在 3\xc2\xb0 方法文档中我找不到如何使用它?只写了如何创建自定义查询,但没有写如何启动它们。

\n\n

非常感谢您的时间和建议。

\n

小智 5

不知道你是否找到了答案,我只是想分享一下我的经验。顺便说一句,如果我的英语不好,请原谅。

注意:我使用 MyBatis 3.4.6 和 Spring 框架。

我必须指定 @Results 注释和每个 @Result ,还是可以使用 java 模型类?

实际上你可以做任何一个。

如果你想使用@Results和@ResultMap,你只需要在一个映射器文件中指定@Results注释一次。诀窍是您需要为要在其他函数中使用的结果指定 id。

使用类的截断版本,例如:

    @Results(id="myResult", value= {
        @Result(property = "id", column = "id"), 
        @Result(property = "inputPath", column = "input_path"),
        @Result(property = "idCategoriaDocumentale", ... })
    List<PreIngest> selectPreIngestsByFilters(@Param("idCatDoc") Long idCatDoc, @Param("nomePacchetto") String nomePacchetto, ...);
Run Code Online (Sandbox Code Playgroud)

然后在另一个函数中,您可以使用@ResultMap,其值引用前面提到的@Results中的id。

    @ResultMap("myResult")
    List<PreIngest> selectPreIngestsBySomethingElse(....);
Run Code Online (Sandbox Code Playgroud)

...,或者我可以使用 java 模型类吗?

您可以使用java模型类作为结果,而不使用@Results和@ResultMap,但您必须确保您的java模型类具有与查询结果相同的属性/字段。数据库表通常具有带有 Snake_case 的字段。由于 java 使用驼峰命名法,因此您必须将设置添加到 mybatis-config.xml 文件中。

这是我通常添加到 mybatis-config.xml 中的内容

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
        <settings>
            <!-- changes from the defaults -->
            <setting name="lazyLoadingEnabled" value="false" />
            <setting name="mapUnderscoreToCamelCase" value="true"/>
            <setting name="jdbcTypeForNull" value="NULL"/>
        </settings>
    </configuration>
Run Code Online (Sandbox Code Playgroud)

重要的是mapUnderscoreToCamelCase,将其设置为 true ,这样您就可以使用 java 模型类,而无需使用 @Results 和 @ResultMap 的麻烦。您可以在MyBatis 3 配置中找到所有设置的说明。

这是使用您的课程的示例,

班上:

public class PreIngest {
    private Long idCategoriaDocumentale;
    private Long idCliente;
    ........ other fields
    ........ setter, getter, etc
}
Run Code Online (Sandbox Code Playgroud)

映射器文件:

List<PreIngest> selectPreIngestsByFilters(@Param("idCatDoc") Long idCatDoc, @Param("nomePacchetto") String nomePacchetto, ...);
Run Code Online (Sandbox Code Playgroud)

现在转向 SqlBuilder。

但如果我将这些放在我的方法中,我将无法访问它们。我需要从方法声明中删除@Param吗?是否需要在没有 @SelectProvider 的情况下调用 SQLBuilder ?

我无法回答您方法中的那些final,因为我从未使用final 参数创建SqlBuilder 类。

对于 SqlBuilder,您必须使用 @SelectProvider、@InsertProvider、@UpdateProvider 或 @DeleteProvider,这取决于您使用的查询。

根据我使用 SQLBuilder 的经验,如果您需要多个参数并使用 Map params 从 SqlBuilder 类访问它,则 @Param 是必要的。如果您不想在映射器文件中使用@Param,那么您需要确保所述映射器函数中只有一个参数。如果您只指定一个参数,则可以使用 java 模型类作为参数。

例如,如果使用您的课程,您可以有一个课程

    public class PersonFilter {
        private Long id;
        private String firstName;
        private String lastName;

        ...... setter, getter, etc
    }
Run Code Online (Sandbox Code Playgroud)

映射器函数

    @SelectProvider(type=PersonSqlBuilder.class, method="selectPersonLike")
    List<Person> selectPersonLike(PersonFilter filter);
Run Code Online (Sandbox Code Playgroud)

SqlBuilder 类

    public class PersonSqlBuilder {

        public String selectPersonLike(PersonFilter filter) {
            return new SQL() {{
                SELECT("P.ID, P.USERNAME, P.PASSWORD, P.FIRST_NAME, P.LAST_NAME");
                FROM("PERSON P");
                if (filter.getId() != null) {
                    WHERE("P.ID like #{id}");
                }
                if (filter.getFirstName() != null) {
                    WHERE("P.FIRST_NAME like #{firstName}");
                }
                if (filter.getLastName() != null) {
                    WHERE("P.LAST_NAME like #{lastName}");
                }
                ORDER_BY("P.LAST_NAME");
            }}.toString();
        }
    }
Run Code Online (Sandbox Code Playgroud)

就是这样。希望我的经验能有所帮助。