英文:
Select Provider Mybatis Error: Parameter 'arg0' not found. Available parameters are [productAttributeDto, param1]
问题
我在使用 Spring Boot 应用程序中集成 Mybatis。我以前使用 ProviderMethodResolver 生成 MySql 查询语句。我的应用程序支持 Mybatis 注解处理器和 XML 处理器。
为了实现这一点,我使用了以下 Mybatis 配置:
在 application.properties 文件中:
mybatis.mapper-locations=classpath*:/repository/**/*Repository.xml
还有一个 MybatisConfiguration.java 文件:
@Configuration
@EnableTransactionManagement
public class MybatisConfiguration {
@Bean
ConfigurationCustomizer mybatisConfigurationCustomizer() {
return new ConfigurationCustomizer() {
@Override
public void customize(org.apache.ibatis.session.Configuration configuration) {
configuration.setMapUnderscoreToCamelCase(true);
configuration.setCacheEnabled(true);
}
};
}
}
通过上述配置,除了 @SelectProvider
的实现之外,所有内容(@Select, @Insert, @ResultMap
)似乎都正常工作。
@SelectProvider
的实现如下:
VariantRepository.java
@Mapper
public interface VariantRepository {
@SelectProvider(type = VariantSqlProvider.class, method = "getProductAttribute")
VariantDto findByProductAttribute(@Param("productAttributeDto") ProductAttributeDto productAttributeDto);
}
我在这里使用了 org.apache.ibatis.annotations.Param
。
ProductAttributeDto.java
@Data
public class ProductAttributeDto {
private Integer productId;
Map<String, String> attributes;
}
VariantSqlProvider.class
public class VariantSqlProvider implements ProviderMethodResolver {
@SuppressWarnings("unused")
public static String getProductAttribute(final ProductAttributeDto productAttributeDto) {
return new SQL() {{
SELECT("*");
FROM("ec_product_variant AS pv");
if (Objects.nonNull(productAttributeDto.getAttributes())) {
for (Entry<String, String> entry : productAttributeDto.getAttributes().entrySet()) {
if (Objects.nonNull(entry.getValue())) {
INNER_JOIN(
new StringBuilder("ec_attributes AS ")
.append(entry.getKey())
.append(" ON ")
.append(entry.getKey()).append(".id = pv.").append(entry.getKey())
.append(" AND ")
.append(entry.getKey()).append(".value=#{productAttributeDto.attributes.").append(entry.getKey())
.append("}").toString()
);
} else {
WHERE("pv." + entry.getKey() + " IS NULL");
}
}
}
if (Objects.nonNull(productAttributeDto.getProductId())) {
WHERE("pv.product_id = #{productAttributeDto.productId}");
}
}}.toString();
}
}
当我调用 findByProductAttribute
方法时,出现如下错误:
org.apache.juli.logging.DirectJDKLog: Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.builder.BuilderException: Error invoking SqlProvider method 'public static java.lang.String com.ecommerce.app.repository.product.sqlprovider.VariantSqlProvider.getProductAttribute(com.ecommerce.app.model.product.ProductAttributeDto)' with specify parameter 'class org.apache.ibatis.binding.MapperMethod$ParamMap'. Cause: org.apache.ibatis.binding.BindingException: Parameter 'arg0' not found. Available parameters are [productAttributeDto, param1]] with root cause
org.apache.ibatis.binding.BindingException: Parameter 'arg0' not found. Available parameters are [productAttributeDto, param1]
at org.apache.ibatis.binding.MapperMethod$ParamMap.get(MapperMethod.java:212)
at org.apache.ibatis.builder.annotation.ProviderSqlSource.extractProviderMethodArguments(ProviderSqlSource.java:223)
我期望生成的 SQL 查询语句是:
SELECT *
FROM ec_product_variant AS pv
INNER JOIN ec_attributes AS color ON color.id = pv.color AND color.value=?
WHERE (pv.size IS NULL AND pv.product_id = ?)
在这里,Mybatis 在寻找 arg0
而不是 productAttributeDto
。有谁能帮助解决这个问题?我在这里做错了什么?提前感谢您的帮助。
英文:
I am using Mybatis with the spring boot application. Where I used to generate MySql query using ProviderMethodResolver. My application supports mybatis annotation processor and XML processor.
To achieve that I used this Mybatis configuration:
In appication.properties file
mybatis.mapper-locations=classpath*:/repository/**/*Repository.xml
and a MybatisConfiguration.java
@Configuration
@EnableTransactionManagement
public class MybatisConfiguration {
@Bean
ConfigurationCustomizer mybatisConfigurationCustomizer() {
return new ConfigurationCustomizer() {
@Override
public void customize(org.apache.ibatis.session.Configuration configuration) {
configuration.setMapUnderscoreToCamelCase(true);
configuration.setCacheEnabled(true);
}
};
}
}
With above configuration, everything(@Select, @Insert, @ResultMap
) seems working fine except implementation of @SelectProvider
.
SelectProvider Implemetation is
VariantRepository.java
@Mapper
public interface VariantRepository {
@SelectProvider(type = VariantSqlProvider.class, method = "getProductAttribute")
VariantDto findByProductAttribute(@Param("productAttributeDto") ProductAttributeDto productAttributeDto);
}
> I am using org.apache.ibatis.annotations.Param
ProductAttributeDto.java
@Data
public class ProductAttributeDto {
private Integer productId;
Map<String, String> attributes;
}
VariantSqlProvider.class
public class VariantSqlProvider implements ProviderMethodResolver {
@SuppressWarnings("unused")
public static String getProductAttribute(final ProductAttributeDto productAttributeDto) {
return new SQL() {{
SELECT("*");
FROM("ec_product_variant AS pv");
if (Objects.nonNull(productAttributeDto.getAttributes())) {
for (Entry<String, String> entry : productAttributeDto.getAttributes().entrySet()) {
if(Objects.nonNull(entry.getValue())) {
INNER_JOIN(
new StringBuilder("ec_attributes AS ")
.append(entry.getKey())
.append(" ON ")
.append(entry.getKey()).append(".id = pv.").append(entry.getKey())
.append(" AND ")
.append(entry.getKey()).append(".value=#{productAttributeDto.attributes.").append(entry.getKey())
.append("}").toString()
);
} else {
WHERE("pv." + entry.getKey() + " IS NULL");
}
}
}
if(Objects.nonNull(productAttributeDto.getProductId())) {
WHERE("pv.product_id = #{productAttributeDto.productId}");
}
}}.toString();
}
}
When I invoke the findByProductAttribute
method, I get an error like this
org.apache.juli.logging.DirectJDKLog: Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.builder.BuilderException: Error invoking SqlProvider method 'public static java.lang.String com.ecommerce.app.repository.product.sqlprovider.VariantSqlProvider.getProductAttribute(com.ecommerce.app.model.product.ProductAttributeDto)' with specify parameter 'class org.apache.ibatis.binding.MapperMethod$ParamMap'. Cause: org.apache.ibatis.binding.BindingException: Parameter 'arg0' not found. Available parameters are [productAttributeDto, param1]] with root cause
org.apache.ibatis.binding.BindingException: Parameter 'arg0' not found. Available parameters are [productAttributeDto, param1]
at org.apache.ibatis.binding.MapperMethod$ParamMap.get(MapperMethod.java:212)
at org.apache.ibatis.builder.annotation.ProviderSqlSource.extractProviderMethodArguments(ProviderSqlSource.java:223)
The SQL query I am expecting to generate is:
SELECT *
FROM ec_product_variant AS pv
INNER JOIN ec_attributes AS color ON color.id = pv.color AND color.value=?
WHERE (pv.size IS NULL AND pv.product_id = ?)
> The query is based on the attributes key-value pair
> in productAttributeDto
Here mybatis is looking for arg0 instead of productAttributeDto.
Can anyone help on this. What am I doing wrong here? Thanks in advance.
答案1
得分: 3
错误是由于映射方法和提供方法之间的参数名称不匹配造成的。
- 映射方法的参数名由
@Param
注解指定,即productAttributeDto
。 - 提供方法中未指定参数名,因此使用默认名称
arg0
。
这些名称必须匹配。
两种解决方案。
- 在提供方法参数上添加
@Param
注解。 - 使用启用了
-parameters
编译器选项构建应用程序。
解决方案1非常简单。
public static String getProductAttribute(
@Param("productAttributeDto") final ProductAttributeDto productAttributeDto) {
解决方案2取决于您构建应用程序的方式。
如果您使用Maven,可能需要在pom.xml中配置maven-compiler-plugin。例如:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
</configuration>
</plugin>
在使用IDE时,您可能需要配置构建设置。
- Eclipse:https://stackoverflow.com/a/38198699/
- IntelliJ IDEA:https://stackoverflow.com/a/39232302/
这样,MyBatis可以从方法签名中检索参数名称,因此您不需要使用@Param
注解(尽管如果您愿意,仍然可以使用@Param
注解)。
结果,映射方法可以更简单...
@SelectProvider(type = VariantSqlProvider.class, method = "getProductAttribute")
VariantDto findByProductAttribute(ProductAttributeDto productAttributeDto);
...并且您问题中的提供方法应该可以正常工作。
英文:
The error is caused by the parameter name mismatch between the mapper method and the provider method.
- The param name of the mapper method is specified by
@Param
annotation i.e.productAttributeDto
. - The param name is not specified in the provider method, so the default name
arg0
is used.
These names must match.
There are two solutions.
- Add
@Param
annotation on the provider method parameter. - Build your application with
-parameters
compiler option enabled.
The solution 1 is pretty straightforward.
public static String getProductAttribute(
@Param("productAttributeDto") final ProductAttributeDto productAttributeDto) {
The solution 2 depends on how you build your application.
If you use Maven, you may need to configure maven-compiler-plugin in the pom.xml. e.g.
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
</configuration>
</plugin>
When using IDE, you might need to configure the build setting.
- Eclipse : https://stackoverflow.com/a/38198699/
- IntelliJ IDEA : https://stackoverflow.com/a/39232302/
This way, MyBatis can retrieve the parameter name from the method signature, so you don't need to use @Param
annotation (you can still use @Param
if you want, though).
As a result, the mapper method can be simpler...
@SelectProvider(type = VariantSqlProvider.class, method = "getProductAttribute")
VariantDto findByProductAttribute(ProductAttributeDto productAttributeDto);
...and the provider method in your question should work as-is.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论