注入参数值以外的任何内容
Inject anything other than param value
我正在尝试使用 @Query
N1QL 查询语法注入值以外的任何内容,但无法正常工作。
这是纯 N1QL 查询:
SELECT * from `my-bucket` WHERE _class = 'my.package.MyModel' AND myParam = 'myValue'
我成功地在 Java 中注入了 一个值 并得到了正确的结果:
// In my repository
@Query("#{#n1ql.selectEntity} WHERE myParam = AND #{#n1ql.filter}")
Collection<MyModel> myCustomSearch(String value);
// In my business code
myRepository.myCustomSearch("myValue");
但是我无法注入任何其他东西(比如参数)。这不起作用:
// In my repository
@Query("#{#n1ql.selectEntity} WHERE = 'myValue' AND #{#n1ql.filter}")
Collection<MyModel> myCustomSearch(String param);
// In my business code
myRepository.myCustomSearch("myParam");
考虑到在纯 N1QL 查询中,值通常用单引号 ('') 包裹起来,注入时不需要,恐怕 spring-data-couchbase 总是包裹注入的元素用单引号或双引号(因此我的查询被转换成
SELECT * from `my-bucket` WHERE _class = 'my.package.MyModel' AND 'myParam' = 'myValue'
这解释了为什么 Couchbase 没有 return 任何结果)。
我错过了什么吗?否则,有没有办法绕过 spring-data-couchbase 的引用注入?
我知道我可以简单地使用 com.couchbase.client.java.Bucket
并在其上调用 query
,但这对我来说失去了 spring-data-couchbase 的全部意义,即始终操纵 POJO 并隐藏 JSON 操纵。
感谢任何帮助!
编辑:查看@simon-baslé 的回答,比我的回答更短更优雅。
我认为我找到了满足我需求的最佳解决方案,形式为 implementing a custom method in my repository。
public interface MyRepositoryCustom {
Collection<MyModel> customN1qlQuery(String query);
}
public interface MyRepository extends CrudRepository<MyModel, String>, MyRepositoryCustom { }
public class MyRepositoryImpl implements MyRepositoryCustom {
@Autowired
RepositoryOperationsMapping templateProvider;
@Override
public Collection<MyModel> customN1qlQuery(String query) {
CouchbaseOperations template = templateProvider.resolve(MyRepository.class, MyModel.class);
return template.findByN1QL(N1qlQuery.simple(query), MyModel.class);
}
}
// In my business code
Collection<MyModel> result = myRepository.customN1qlQuery("select META().id AS _ID, META().cas AS _CAS, * from `" + bucket.name() + "` where _class = '"
+ MyModel.class.getCanonicalName() + "' and " + myCustomParam + " = '" + myCustomValue + "'");
我一直在操作 POJO,但我可以完全控制 N1QL 查询语句。唯一(次要)的缺点是我无法再注入 Spring SpEL syntax(例如 #{#n1ql.selectEntity}
来检索完整实体,或 #{#n1ql.filter}
来过滤实体 class 名称)。我发现了等同的文字(如我上面的示例所示),所以我可以接受。
</code> 实际上只是将 N1QL 语法用于参数化语句。我没有对其进行广泛测试,但您可以在此处使用 SpEL。在 SpEL 中使用方法参数的方法是使用 <code>#{[x]}
语法,其中 x
是要使用的参数的基于 0 的索引。
混合使用这两种方法时要小心:一旦在语句中检测到 $x
,Spring Data Couchbase 将使用 all 方法参数作为填充 $x 占位符的数组。所以第一个参数将映射到 </code>,第二个参数将映射到 <code>
,等等...
所以要同时使用这两种语法(一种动态选择字段名称,另一种让 N1QL 注入搜索到的值),您必须这样写:
@Query("#{#n1ql.selectEntity} WHERE #{[0]} = AND #{#n1ql.filter}")
public List<Entity> findAllBySomeCriteria(String fieldName, String value);
注意 #{[0]}
和 </code> 如何都指向 <code>fieldName
参数,因此使用的 N1QL 占位符是 </code>,指向 <code>value
.
我正在尝试使用 @Query
N1QL 查询语法注入值以外的任何内容,但无法正常工作。
这是纯 N1QL 查询:
SELECT * from `my-bucket` WHERE _class = 'my.package.MyModel' AND myParam = 'myValue'
我成功地在 Java 中注入了 一个值 并得到了正确的结果:
// In my repository
@Query("#{#n1ql.selectEntity} WHERE myParam = AND #{#n1ql.filter}")
Collection<MyModel> myCustomSearch(String value);
// In my business code
myRepository.myCustomSearch("myValue");
但是我无法注入任何其他东西(比如参数)。这不起作用:
// In my repository
@Query("#{#n1ql.selectEntity} WHERE = 'myValue' AND #{#n1ql.filter}")
Collection<MyModel> myCustomSearch(String param);
// In my business code
myRepository.myCustomSearch("myParam");
考虑到在纯 N1QL 查询中,值通常用单引号 ('') 包裹起来,注入时不需要,恐怕 spring-data-couchbase 总是包裹注入的元素用单引号或双引号(因此我的查询被转换成
SELECT * from `my-bucket` WHERE _class = 'my.package.MyModel' AND 'myParam' = 'myValue'
这解释了为什么 Couchbase 没有 return 任何结果)。
我错过了什么吗?否则,有没有办法绕过 spring-data-couchbase 的引用注入?
我知道我可以简单地使用 com.couchbase.client.java.Bucket
并在其上调用 query
,但这对我来说失去了 spring-data-couchbase 的全部意义,即始终操纵 POJO 并隐藏 JSON 操纵。
感谢任何帮助!
编辑:查看@simon-baslé 的回答,比我的回答更短更优雅。
我认为我找到了满足我需求的最佳解决方案,形式为 implementing a custom method in my repository。
public interface MyRepositoryCustom {
Collection<MyModel> customN1qlQuery(String query);
}
public interface MyRepository extends CrudRepository<MyModel, String>, MyRepositoryCustom { }
public class MyRepositoryImpl implements MyRepositoryCustom {
@Autowired
RepositoryOperationsMapping templateProvider;
@Override
public Collection<MyModel> customN1qlQuery(String query) {
CouchbaseOperations template = templateProvider.resolve(MyRepository.class, MyModel.class);
return template.findByN1QL(N1qlQuery.simple(query), MyModel.class);
}
}
// In my business code
Collection<MyModel> result = myRepository.customN1qlQuery("select META().id AS _ID, META().cas AS _CAS, * from `" + bucket.name() + "` where _class = '"
+ MyModel.class.getCanonicalName() + "' and " + myCustomParam + " = '" + myCustomValue + "'");
我一直在操作 POJO,但我可以完全控制 N1QL 查询语句。唯一(次要)的缺点是我无法再注入 Spring SpEL syntax(例如 #{#n1ql.selectEntity}
来检索完整实体,或 #{#n1ql.filter}
来过滤实体 class 名称)。我发现了等同的文字(如我上面的示例所示),所以我可以接受。
</code> 实际上只是将 N1QL 语法用于参数化语句。我没有对其进行广泛测试,但您可以在此处使用 SpEL。在 SpEL 中使用方法参数的方法是使用 <code>#{[x]}
语法,其中 x
是要使用的参数的基于 0 的索引。
混合使用这两种方法时要小心:一旦在语句中检测到 $x
,Spring Data Couchbase 将使用 all 方法参数作为填充 $x 占位符的数组。所以第一个参数将映射到 </code>,第二个参数将映射到 <code>
,等等...
所以要同时使用这两种语法(一种动态选择字段名称,另一种让 N1QL 注入搜索到的值),您必须这样写:
@Query("#{#n1ql.selectEntity} WHERE #{[0]} = AND #{#n1ql.filter}")
public List<Entity> findAllBySomeCriteria(String fieldName, String value);
注意 #{[0]}
和 </code> 如何都指向 <code>fieldName
参数,因此使用的 N1QL 占位符是 </code>,指向 <code>value
.