stored resultmap parametertype parameter example collection java mybatis

java - resultmap - parametertype mybatis int



¿Puedo pasar una lista como parámetro a un mapeador de MyBatis? (4)

Con un poco de sobrecarga, puede usar JAVA para crear una cadena dinámica después de procesar la Lista.

  1. Defina un Proveedor Select donde puede construir su consulta dinámica:

    @SelectProvider(type = com.data.sqlprovider.EmployeeSQLBuilder.class, method = "selectSpecificEmployees") List<Employee> selectSpecificEmployees(@Param("employeeIds") List<Integer> employeeIds);

  2. En com.data.sqlprovider.EmployeeSQLBuilder.class, utilizando StringBuilder, genere la consulta

    public String selectSpecificEmployees(Map<String, Object> parameters) { List<Integer> employeeIds = (List<Integer>) parameters.get("employeeIds"); StringBuilder builder = new StringBuilder("SELECT id, name FROM employees where id IN ("); for (int i : employeeIds) { builder.append(i + ","); } builder.deleteCharAt(builder.length() - 1); builder.append(")"); System.out.println(builder.toString()); return builder.toString(); }

Estoy tratando de definir una simple anotación @Select en MyBatis para obtener una colección de objetos basada en criterios definidos por una cláusula IN. El SQL se ve algo así como:

SELECT * FROM employees WHERE employeeID IN (1, 2, 3);

La lista se genera de forma dinámica, por lo que no sé cuántos parámetros tendrá. Me gustaría simplemente pasar en una List de valores, algo como:

@Select("SELECT * FROM employees WHERE employeeID IN( #{employeeIds} )") List<Employee> selectSpecificEmployees(@Param("employeeIds") List<Integer> employeeIds);

Estoy creando una instancia del Mapper donde se define la anotación anterior y la llamo de la siguiente manera:

List<Integer> empIds = Arrays.asList(1, 2, 3); List<Employee> result = mapper.selectSpecificEmployees(empIds);

He descubierto que esto no funciona.

org.apache.ibatis.exceptions.PersistenceException:
### Error al consultar la base de datos. Causa: java.lang.NullPointerException
### El error puede involucrar
com.mycompany.MySourceMapper.selectSpecificEmployees-Inline
### Ocurrió un error al configurar los parámetros ### Causa: java.lang.NullPointerException en org.apache.ibatis.exceptions.ExceptionFactory.wrapException (ExceptionFactory.java:8) en org.apache.ibatis.session.defaults.DefaultSqlSession .selectList (DefaultSqlSession.java:77) en org.apache.ibatis.session.defaults.DefaultSqlSession.selectList (DefaultSqlSession.java:69) en org.apache.ibatis.binding.MapperMethod.executeForList (MapperMethod.java:85.85). org.apache.ibatis.binding.MapperMethod.execute (MapperMethod.java:65) en org.apache.ibatis.binding.MapperProxy.invoke (MapperProxy.java:35) en $ Proxy23.selectSpecificProductTypes (Fuente desconocida) en com.mycompany .MySourceMapperDebug.testSelectSpecificEmployees (MySourceMapperDebug.java:60) en sun.reflect.NativeMethodAccessorImpl.invoke.payunidad.payas.payas.payas.payas.payas.payas.payas.payas.payas.payas.payas.payas.payas.payas.payas.payas.payas.payas.payas.payas.payas.payas.payas.payas lang.reflect.Method.invoke (Fuente desconocida) en junit.framework.Te stCase.runTest (TestCase.java:154) en junit.framework.TestCase.runBare (TestCase.java:127) en junit.framework.TestResult $ 1.protect (TestResult.java:106) en junit.framework.TestResult.runProtected ( TestResult.java:124) en junit.framework.TestResult.run (TestResult.java:109) en junit.framework.TestCase.run (TestCase.java:118) en junit.framework.TestSuite.runTest (TestSuite.java:20) ) en junit.framework.TestSuite.run (TestSuite.java:203) en org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run (JUnit3TestReference.java:130) en org.eclipse.jjcc.cjc.jj.jj.jj.jj.jj.jun.jjc.jun.jjc.jun. junit.runner.TestExecution.run (TestExecution.java:38) en org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests (RemoteTestRunner.java:467) en org.eclipse.jdt.internal.junit.run.run.r. RemoteTestRunner.runTests (RemoteTestRunner.java:683) en org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run (RemoteTestRunner.nunpunidad) RemoteTestRunner.java:197) Causado por: java.lan g.NullPointerException en org.apache.ibatis.type.UnknownTypeHandler.setNonNullParameter (UnknownTypeHandler.java:21) en org.apache.ibatis.type.BaseTypeHandler.setParameter (BaseTypeHandler.java:23) en la tienda de correos. parameters.DefaultParameterHandler.setParameters (DefaultParameterHandler.java:73) en la org.apache.ibatis.executor.statement.PreparedStatement.parp.paramer.parameter.parametron_parameter.parametron_parameter.pañol.parameter. java: 43) en org.apache.ibatis.executor.SimpleExecutor.prepareStatement (SimpleExecutor.java:56) en org.apache.ibatis.executor.SimpleExecutor.doQuery (SimpleExecutor.java:40) en org.apache.ibatis.executor .BaseExecutor.queryFromDatabase (BaseExecutor.java:216) en org.apache.ibatis.executor.BaseExecutor.query (BaseExecutor.java:95) en org.apache.ibatis.executor.CachingExecutor.query (CachingExecutor.java:72) en sun.reflect.NativeMethodAccessorImpl.invoke0 (Método nativo) en sun.reflec t.NativeMethodAccessorImpl.invoke (Fuente desconocida) en sun.reflect.DelegatingMethodAccessorImpl.invoke (Fuente desconocida) en java.lang.reflect.Method.invoke (Fuente desconocida) en org.apache.ibatis.plugin.Invocation.Invocation. java: 31)
... 36 más

Creo que el problema está en la propia anotación. Esto parece que sería un requisito bastante común. ¿Debo convertir la List en una String y pasarla como un parámetro de String lugar de una List<Integer> ? ¿O hay alguna otra sintaxis para pasar una List como parámetro a una anotación de MyBatis?


Estoy enfrentando los mismos problemas recientemente. A mi entender, prefieres usar el mapeador de Java lugar de XML , que es el mismo aquí.

Lo siguiente es lo que estoy haciendo para lidiar con eso usando: SqlBuilder .

La clase de constructor de sql:

public class EmployeeSqlBuilder { public String getEmployees(final List employeeIds) { String strSQL = new SQL() {{ SELECT("*"); FROM("employees"); if (employeeIds != null) { WHERE(getSqlConditionCollection("employeeID", employeeIds)); } }}.toString(); return strSQL; } private String getSqlConditionCollection(String field, List conditions) { String strConditions = ""; if (conditions != null && conditions.size() > 0) { int count = conditions.size(); for (int i = 0; i < count; i++) { String condition = conditions.get(i).toString(); strConditions += condition; if (i < count - 1) { strConditions += ","; } } return field + " in (" + strConditions + ")"; } else { return "1=1"; } } }

El mapeador:

@SelectProvider(type = EmployeeSqlBuilder.class, method = "getEmployees") List<RecordSubjectEx> getEmployees(@Param("employeeIds") List employeeIds);

Eso es.

EmployeeSqlBuilder generará dinámicamente la instrucción sql. Estoy usando una función getSqlConditionCollection para hacer la manipulación lógica. Por supuesto, puede encapsular getSqlConditionCollection como una función estática en una clase, que es lo que estoy haciendo en un proyecto real, luego puede usarlo fácilmente desde otros SqlBuilder.


Nunca he usado anotaciones y MyBatis antes; Siempre he seguido la ruta del archivo de configuración xml (no insinuando que haya algo de malo en el uso de anotaciones; solo te explico que no puedo ayudarte).

Dicho esto, la página 46 de la guía del usuario de MyBatis :

para cada

Otra necesidad común para SQL dinámico es la necesidad de iterar sobre una colección, a menudo para construir una condición IN. Por ejemplo:

<select id="selectPostIn" resultType="domain.blog.Post"> SELECT * FROM POST P WHERE ID in <foreach item="item" index="index" collection="list" open="(" separator="," close=")"> #{item} </foreach> </select>

El elemento foreach es muy poderoso y le permite especificar una colección, declarar elementos y variables de índice que se pueden usar dentro del cuerpo del elemento. También le permite especificar cadenas de apertura y cierre, y agregar un separador para ubicar entre iteraciones. El elemento es inteligente en el sentido de que no agrega separadores adicionales accidentalmente.


Si desea utilizar foreach y anotaciones, puede utilizar esta sintaxis:

@Select("<script>" + "SELECT * FROM employees WHERE employeeID IN " + "<foreach item=''item'' index=''index'' collection=''employeeIds''" + " open=''('' separator='','' close='')''>" + " #{item}" + "</foreach>" + "</script>") List<Employee> selectSpecificEmployees(@Param("employeeIds") List<Integer> employeeIds);

(Copiado de esa answer )