【Spring连载】使用Spring Data访问 MongoDB----对象映射之非包装类型

【Spring连载】使用Spring Data访问 MongoDB----对象映射之非包装类型

未包装实体用于在Java领域模型中设计值对象,其属性被展平(flattened)到父类的MongoDB Document中。

一、未包装类型映射

考虑下面的域模型,其中User.name用@Unwrapped注解。@Unwrapped注解表示UserName的所有属性都应该被展平到拥有name属性的user document中。
例1:展开对象的示例代码

java 复制代码
class User {

    @Id
    String userId;

    @Unwrapped(onEmpty = USE_NULL) --------1
    UserName name;
}

class UserName {

    String firstname;

    String lastname;

}
json 复制代码
{
  "_id" : "1da2ba06-3ba7",
  "firstname" : "Emma",
  "lastname" : "Frost"
}

1. 加载name属性时,如果firstname和lastname都为null或不存在,则其值设置为null。通过使用onEmpty=USE_EMPTY,将创建一个空的UserName,其属性可能为null值。

对于不太详细的可嵌入类型声明,请使用"@Unwrapped.Nullable"和"@Unwrapped.Empty",而不是"@Unwrapped(onEmpty = USE_NULL)"和"@Unwrapped(onEmpty = USE_EMPTY)"。这两个注解都使用JSR-305"@javax.annotation.Nonnull"进行元注解,以帮助进行可空性检查。

可以在展开的对象中使用复杂类型。但是,这些字段本身不能是,也不能包含未展开的字段。

二、未包装类型字段名

通过使用@Unwrapped注解的可选前缀属性,可以多次展开值对象。通过这样做,所选择的前缀被附加到未包装对象中的每个属性或@Field("...")名称之前。请注意,如果多个属性呈现为相同的字段名称,则值将相互覆盖。
例2:带有名称前缀的展开对象的示例代码

java 复制代码
class User {

    @Id
    String userId;

    @Unwrapped.Nullable(prefix = "u_") --------1
    UserName name;

    @Unwrapped.Nullable(prefix = "a_") --------2
    UserName name;
}

class UserName {

    String firstname;

    String lastname;
}
json 复制代码
{
  "_id" : "a6a805bd-f95f",
  "u_firstname" : "Jean",             --------1
  "u_lastname" : "Grey",
  "a_firstname" : "Something",        --------2
  "a_lastname" : "Else"
}

1. UserName的所有属性都以u_为前缀。
2. UserName的所有属性都以a_为前缀。

在同一属性上组合@Field注解和@Unwrapped是没有意义的,因此会导致错误。在任何展开的类型属性上使用@Field是完全有效的方法。
例3:带有@Field注解的展开对象示例代码

java 复制代码
public class User {

	@Id
    private String userId;

    @Unwrapped.Nullable(prefix = "u-") --------1
    UserName name;
}

public class UserName {

	@Field("first-name")              --------2
    private String firstname;

	@Field("last-name")
    private String lastname;
}
json 复制代码
{
  "_id" : "2647f7b9-89da",
  "u-first-name" : "Barbara",        --------2 
  "u-last-name" : "Gordon"
}

1. UserName的所有属性都以u-为前缀。
2. 最终字段名是@Unwrapped(前缀)和@Field(名称)拼接的结果。

三、查询未包装对象

可以在类型和字段级别上对展开的属性定义查询,因为提供的条件与域类型匹配。在呈现实际查询时,将考虑前缀和潜在的自定义字段名。使用展开对象的属性名称来匹配所有包含的字段,如下面的示例所示。
例4:查询未包装对象

java 复制代码
UserName userName = new UserName("Carol", "Danvers")
Query findByUserName = query(where("name").is(userName));
User user = template.findOne(findByUserName, User.class);
json 复制代码
db.collection.find({
  "firstname" : "Carol",
  "lastname" : "Danvers"
})

也可以直接使用未包装对象的属性名来处理它的任何字段,如下面的代码片段所示。
例5:查询未包装对象的字段

java 复制代码
Query findByUserFirstName = query(where("name.firstname").is("Shuri"));
List<User> users = template.findAll(findByUserFirstName, User.class);
json 复制代码
db.collection.find({
  "firstname" : "Shuri"
})

3.1 按未包装字段排序

未包装对象的字段可用于通过其属性路径进行排序,如下面的示例所示。
例6:对未包装字段进行排序

java 复制代码
Query findByUserLastName = query(where("name.lastname").is("Romanoff"));
List<User> user = template.findAll(findByUserName.withSort(Sort.by("name.firstname")), User.class);
json 复制代码
db.collection.find({
  "lastname" : "Romanoff"
}).sort({ "firstname" : 1 })

虽然可以,但使用未包装对象本身作为排序条件会以不可预测的顺序包含其所有字段,并可能导致不准确的排序。

3.2 未包装对象的字段投影

未包装对象的字段可以作为一个整体或通过单个字段进行投影,如下面的示例所示。
例7:未包装对象上的投影

java 复制代码
Query findByUserLastName = query(where("name.firstname").is("Gamora"));
findByUserLastName.fields().include("name");  --------1
List<User> user = template.findAll(findByUserName, User.class);
json 复制代码
db.collection.find({
  "lastname" : "Gamora"
},
{
  "firstname" : 1,
  "lastname" : 1
})

1. 未包装对象上的字段投影包括其所有属性。

例8:未包装对象的字段上的投影

java 复制代码
Query findByUserLastName = query(where("name.lastname").is("Smoak"));
findByUserLastName.fields().include("name.firstname");                  --------1 
List<User> user = template.findAll(findByUserName, User.class);
json 复制代码
db.collection.find({
  "lastname" : "Smoak"
},
{
  "firstname" : 1
})

1. 未包装对象上的字段投影包括其所有属性。

3.3 未包装对象的Query By Example

未包装对象可以像任何其他类型一样在Example probe中使用。请查看Query By Example一节,以了解有关此特性的更多信息。

3.4 未包装对象的存储库查询

Repository抽象允许对未包装对象的字段以及整个对象派生查询。
例9:对未包装对象的存储库查询

java 复制代码
interface UserRepository extends CrudRepository<User, String> {

	List<User> findByName(UserName username);         --------1

	List<User> findByNameFirstname(String firstname); --------2
}

1. 对未包装对象的所有字段进行匹配。
2. 与firstname匹配。

即使存储库create-query-indexes命名空间属性设置为true,也会挂起未包装对象的索引创建。

四、更新未包装对象

五、未包装对象上的聚合

六、未包装对象上的索引

相关推荐
守护者1706 分钟前
JAVA学习-练习试用Java实现“一个词频统计工具 :读取文本文件,统计并输出每个单词的频率”
java·学习
bing_15817 分钟前
Spring Boot 中ConditionalOnClass、ConditionalOnMissingBean 注解详解
java·spring boot·后端
ergdfhgerty19 分钟前
斐讯N1部署Armbian与CasaOS实现远程存储管理
java·docker
勤奋的知更鸟32 分钟前
Java性能测试工具列举
java·开发语言·测试工具
三目君36 分钟前
SpringMVC异步处理Servlet
java·spring·servlet·tomcat·mvc
用户05956611920936 分钟前
Java 基础篇必背综合知识点总结包含新技术应用及实操指南
java·后端
fie888937 分钟前
Spring MVC扩展与SSM框架整合
java·spring·mvc
GeekAGI41 分钟前
通过 MongoDB URL 连接到 MongoDB 数据库
mongodb
不太可爱的叶某人44 分钟前
【学习笔记】深入理解Java虚拟机学习笔记——第3章 垃圾收集器与内存分配策略
java·笔记·学习
YuTaoShao1 小时前
Java八股文——JVM「类加载篇」
java·开发语言·jvm