我正在将一个实体保留在CouchBase存储库中并尝试查询它。该实体如下所示:
@Document(expiry = 0)
public class GsJsonStore implements Serializable {
private static final long serialVersionUID = 7133072282172062535L;
@Id @GeneratedValue(strategy=GenerationType.AUTO)
private long id;
@Field
private Map<String,Object> _object;
@Field
private String _subject;
@Field
private String _predicate;
//Getters and Setters
}
我正在使用 CouchbaseOperations 模板上的 N1QL 查询来查询实体,如下所示:
String query1 = "SELECT META(default).id as _ID, META(default).cas as _CAS, default.* FROM default WHERE "+key+"="+"'"+value+"'";
List<GsJsonStore> list = operations.findByN1QL(N1qlQuery.simple(query1), GsJsonStore.class);
我正在_object图中查询 K-V 对。我收到一个错误:No mapping metadata found for java.lang.Object
为什么会这样?另外,我正在将一个 json 对象存储为 Couchbase 中的Map<String,Object>
,我尝试使用 jackson JsonNode
类型,但该对象还存储了与类相关的元数据。有没有更好的数据类型来表示 json 类型?
编辑
存储在 Couchbase 中的数据:
{
"_object" : {
"Name" : "Kapil",
"Age" : {
"Nested" : 21
}
},
"_subject" : "Subject",
"_predicate" : "Predicate"
}
我要找的钥匙是_object。名称和值为"卡皮尔"
如此处所述,您应该覆盖默认的SPMappingCouchbaseConverter。
这是我解决问题的方法:
@Bean
public MappingCouchbaseConverter mappingCouchbaseConverter() throws Exception {
return new MyMappingCouchbaseConverter(couchbaseMappingContext());
}
private class MyMappingCouchbaseConverter extends MappingCouchbaseConverter {
MyMappingCouchbaseConverter(MappingContext<? extends CouchbasePersistentEntity<?>, CouchbasePersistentProperty> mappingContext) {
super(mappingContext);
}
@Override
@SuppressWarnings("unchecked")
protected <R> R read(final TypeInformation<R> type, final CouchbaseDocument source, final Object parent) {
if (Object.class == typeMapper.readType(source, type).getType()) {
return (R) source.export();
} else {
return super.read(type, source, parent);
}
}
}
如果你绝对需要Map
:
看起来问题是双重的:
- 使用带有参数的构造函数通过反射重新实例化在我的测试中似乎效果不佳,因此我会添加一个私有的空构造函数
private GsJsonStore() {}
。 - 您存储的
Map
包含另一个嵌套级别,也作为通用Map
。这对于框架在反序列化时处理来说是有问题的。
您可以尝试将"Age"展平到顶级_object
映射中,或者为"Age"条目创建一个专用类(只需使用int类型的Nested
字段)并存储它。请注意,在后一种情况下,框架应将_class
元数据添加到存储的"Age"JSON 中,这解释了在这种情况下它如何在以后对其进行反序列化。
如果您可以比Map
更具体地建模:
最好的方法仍然是创建一个适当的GsEntity
类,没有泛型集合/映射,而是命名属性(以及可能有意义的子值实体类)。
这将缓解 Map
的问题,并允许通过在存储库界面中添加方法签名来自动创建查询。像这样:
public class ContentObject {
private String name;
private int age;
public ContentObject(String name, int age) {
this.name = name;
this.age = age;
}
}
@Document(expiry = 0)
public class GsEntity implements Serializable {
private static final long serialVersionUID = 7133072282172062535L;
@Id
private String id;
@Field
private ContentObject object;
@Field
private String subject;
@Field
private String predicate;
//EMPTY CONSTRUCTOR
//Getters and Setters
}
public interface GsEntityRepository extends CouchbaseRepository<GsEntity, String> {
@Query
List<GsEntity> findByObjectNameEquals(String nameValue);
}
请注意,属性已被重命名以删除下划线,因为它不遵循 Java 命名约定,并且会阻止接口的方法正确映射到属性。
该方法大致分析如下:findBy
Object
Name
Equals
.这将转换为GsEntity
对象的 SELECT,object
字段具有与作为参数传递的字符串具有相同值的name
字段。