【问题标题】:No mapping metadata found for java.lang.Object - Couchbase找不到 java.lang.Object 的映射元数据 - Couchbase
【发布时间】:2016-06-30 09:40:36
【问题描述】:

我在 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

为什么会这样?此外,我在 Couchbase 中将 json 对象存储为 Map&lt;String,Object&gt;,我尝试使用 jackson JsonNode 类型,但该对象还存储了与类相关的元数据。有更好的数据类型来表示json类型吗?

编辑

存储在 Couchbase 中的数据:

{
"_object" : {
"Name" : "Kapil",
"Age" : {
"Nested" : 21
}
},
"_subject" : "Subject",
"_predicate" : "Predicate"
}

我要查找的键是 _object.Name,值是 'Kapil'

【问题讨论】:

  • 您存储在地图中的数据类型是什么?您的查询中keyvalue 的类型和值是什么?
  • 在旁注中,有一个长的 id 是可行的,但最好有一个更精心制作的字符串 id(例如,带有“gsonStore”前缀和一个数字)。默认情况下,所有文档都存储在 Couchbase 中的同一个存储桶中,因此数字 id 大大增加了冲突和覆盖的机会,如果您不格外小心,请始终为所有类型的实体的所有 id 使用相同的源...
  • 我已编辑问题以显示我存储在地图中的数据。感谢您对长 ID 的提醒,我们会做出改变!
  • 另一个问题是您所做的查询不包括 WHERE 子句中 _class 字段的过滤器:应该是 WHERE "+path+"="+"'"+value+"' AND _class = '" + GsJsonStore.class.getName() + "'"
  • _object 中的数据真的总是在变化,或者您是否能够创建一个类(例如SubObject),它对所有可能的数据字段都具有(可为空的)属性?您也可以尝试向GsJsonStore 添加一个空的私有构造函数吗?

标签: couchbase spring-data-couchbase


【解决方案1】:

正如here 解释的那样,您应该覆盖默认的 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);
        }
    }

}

【讨论】:

  • 我遇到了同样的错误,当我粘贴此代码时,@Bean 内的 return 语句开始出现错误。我应该在 couchbaseMappingContext() 中传递什么
  • 如果地图中有这样的有效载荷,这种方法将失败。 "myCustomMap":{"array":[{}]}
【解决方案2】:

如果你绝对需要Map

看起来问题是双重的:

  1. 使用带参数的构造函数通过反射重新实例化在我的测试中似乎效果不佳,因此我将添加一个私有的空构造函数private GsJsonStore() {}
  2. 您存储的Map 包含另一个级别的嵌套,作为通用Map 也是如此。这对于框架在反序列化时处理是有问题的。

您可以尝试将“Age”扁平化到顶级 _object 映射中,或者为“Age”条目创建一个专用类(只需使用 int 类型的 Nested 字段)并存储它。请注意,在后一种情况下,框架应将 _class 元数据添加到存储的“年龄”JSON 中,这解释了在这种情况下它如何在以后设法反序列化它。

如果你可以比Map更具体地建模

最好的方法仍然是创建一个适当的GsEntity 类,没有通用集合/映射但命名属性(以及可能对子值有意义的实体类)。

这将缓解Maps 的问题,并允许通过简单地在存储库接口中添加方法签名来自动创建查询。类似的东西:

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 命名约定,并且会阻止接口的方法正确映射到属性。

方法大致分析如下:findByObjectNameEquals。 这转换为GsEntity 对象的SELECT,其中object 字段有一个name 字段,其值与作为参数传递的字符串相同。

【讨论】:

  • 我提供的示例 json 中的 _object 字段可以是任何 json 对象,它是无模式的,因此我需要使用 Map/JsonObject/JsonNode(Jackson) 来存储它。
猜你喜欢
  • 2023-03-29
  • 2016-05-14
  • 1970-01-01
  • 2015-10-27
  • 2011-01-21
  • 2019-04-09
  • 1970-01-01
  • 1970-01-01
  • 2016-03-31
相关资源
最近更新 更多