【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,也会挂起未包装对象的索引创建。

四、更新未包装对象

五、未包装对象上的聚合

六、未包装对象上的索引

相关推荐
2402_8575893630 分钟前
“衣依”服装销售平台:Spring Boot框架的设计与实现
java·spring boot·后端
吾爱星辰1 小时前
Kotlin 处理字符串和正则表达式(二十一)
java·开发语言·jvm·正则表达式·kotlin
哎呦没2 小时前
大学生就业招聘:Spring Boot系统的架构分析
java·spring boot·后端
编程、小哥哥2 小时前
netty之Netty与SpringBoot整合
java·spring boot·spring
IT学长编程3 小时前
计算机毕业设计 玩具租赁系统的设计与实现 Java实战项目 附源码+文档+视频讲解
java·spring boot·毕业设计·课程设计·毕业论文·计算机毕业设计选题·玩具租赁系统
莹雨潇潇3 小时前
Docker 快速入门(Ubuntu版)
java·前端·docker·容器
杨哥带你写代码3 小时前
足球青训俱乐部管理:Spring Boot技术驱动
java·spring boot·后端
郭二哈4 小时前
C++——模板进阶、继承
java·服务器·c++
A尘埃4 小时前
SpringBoot的数据访问
java·spring boot·后端
yang-23074 小时前
端口冲突的解决方案以及SpringBoot自动检测可用端口demo
java·spring boot·后端