解包类型

未包装的实体用于设计 Java 域模型中的值对象,其属性被扁平化为父级的 MongoDB Document。spring-doc.cadn.net.cn

未包类型映射

请考虑以下域模型,其中User.name被注释为@Unwrapped. 这@Unwrappedannotation 表示UserName应该展平为user文档,该文档拥有name财产。spring-doc.cadn.net.cn

示例 1.解包对象的示例代码
class User {

    @Id
    String userId;

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

class UserName {

    String firstname;

    String lastname;

}
{
  "_id" : "1da2ba06-3ba7",
  "firstname" : "Emma",
  "lastname" : "Frost"
}
1 加载name属性,其值设置为null如果两者都firstnamelastname要么null或不存在。 通过使用onEmpty=USE_EMPTY空的UserName,具有潜力null值。

对于不太详细的可嵌入类型声明,请使用@Unwrapped.Nullable@Unwrapped.Empty相反@Unwrapped(onEmpty = USE_NULL)@Unwrapped(onEmpty = USE_EMPTY). 这两个注解都使用 JSR-305 进行元注解@javax.annotation.Nonnull以帮助进行可为 null 性检查。spring-doc.cadn.net.cn

可以在未包的对象中使用复杂类型。 但是,这些字段本身不得包含未包装的字段。spring-doc.cadn.net.cn

Unwrapped Types 字段名称

值对象可以使用可选的prefix属性的@Unwrapped注解。 通过剂量,以便将所选前缀添加到每个属性前面,或者@Field("…")name 在未包的对象中。 请注意,如果多个属性呈现为相同的字段名称,则值将相互覆盖。spring-doc.cadn.net.cn

示例 2.带有 name prefix 的 unwrapped object 的示例代码
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;
}
{
  "_id" : "a6a805bd-f95f",
  "u_firstname" : "Jean",             (1)
  "u_lastname" : "Grey",
  "a_firstname" : "Something",        (2)
  "a_lastname" : "Else"
}
1 的所有属性UserName前缀为u_.
2 的所有属性UserName前缀为a_.

在结合@Fieldannotation 替换为@Unwrapped在同一个属性上没有意义,因此会导致错误。 这是一种完全有效的使用@Field在任何 Unwrapped Types 属性上。spring-doc.cadn.net.cn

例 3.使用@Field注解
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;
}
{
  "_id" : "2647f7b9-89da",
  "u-first-name" : "Barbara",         (2)
  "u-last-name" : "Gordon"
}
1 的所有属性UserName前缀为u-.
2 最终字段名称是连接的结果@Unwrapped(prefix)@Field(name).

对 Unwrapped Objects 的查询

可以在类型级别和字段级别定义对 unwrapped properties 的查询,就像提供的Criteria与域类型匹配。 在呈现实际查询时,将考虑前缀和可能的自定义字段名称。 使用未打包对象的属性名称与所有包含的字段匹配,如以下示例所示。spring-doc.cadn.net.cn

示例 4.查询未打包的对象
UserName userName = new UserName("Carol", "Danvers")
Query findByUserName = query(where("name").is(userName));
User user = template.findOne(findByUserName, User.class);
db.collection.find({
  "firstname" : "Carol",
  "lastname" : "Danvers"
})

也可以使用其属性名称直接寻址未包装对象的任何字段,如下面的代码片段所示。spring-doc.cadn.net.cn

例 5.查询未包对象的字段
Query findByUserFirstName = query(where("name.firstname").is("Shuri"));
List<User> users = template.findAll(findByUserFirstName, User.class);
db.collection.find({
  "firstname" : "Shuri"
})

按未包装的字段排序。

未包包对象的字段可用于通过其属性路径进行排序,如以下示例所示。spring-doc.cadn.net.cn

例 6.对未包装的字段进行排序
Query findByUserLastName = query(where("name.lastname").is("Romanoff"));
List<User> user = template.findAll(findByUserName.withSort(Sort.by("name.firstname")), User.class);
db.collection.find({
  "lastname" : "Romanoff"
}).sort({ "firstname" : 1 })

尽管有可能,但使用未包装的对象本身作为排序条件会以不可预测的顺序包含其所有字段,并且可能会导致排序不准确。spring-doc.cadn.net.cn

展开对象上的场投影

解包对象的字段可以作为整体或通过单个字段进行投影,如以下示例所示。spring-doc.cadn.net.cn

例 7.在未包的对象上投影。
Query findByUserLastName = query(where("name.firstname").is("Gamora"));
findByUserLastName.fields().include("name");                             (1)
List<User> user = template.findAll(findByUserName, User.class);
db.collection.find({
  "lastname" : "Gamora"
},
{
  "firstname" : 1,
  "lastname" : 1
})
1 未包对象上的字段投影包括其所有属性。
例 8.在未包对象的字段上投影。
Query findByUserLastName = query(where("name.lastname").is("Smoak"));
findByUserLastName.fields().include("name.firstname");                   (1)
List<User> user = template.findAll(findByUserName, User.class);
db.collection.find({
  "lastname" : "Smoak"
},
{
  "firstname" : 1
})
1 未包对象上的字段投影包括其所有属性。

Query By Example 对未包装的对象。

解包的对象可以在Example探测。 请查看 Query By Example 部分,以了解有关此功能的更多信息。spring-doc.cadn.net.cn

存储库 对未打包对象的查询。

Repositoryabstraction 允许对 unwrapped objects 的字段以及整个 object 进行派生查询。spring-doc.cadn.net.cn

例 9.对未打包对象的存储库查询。
interface UserRepository extends CrudRepository<User, String> {

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

	List<User> findByNameFirstname(String firstname); (2)
}
1 与未打包对象的所有字段匹配。
2 firstname.

即使存储库create-query-indexesnamespace 属性设置为true.spring-doc.cadn.net.cn

更新已解包的对象

解包的对象可以像属于域模型的任何其他对象一样进行更新。 映射层负责将结构展平到其周围环境中。 可以更新未包装对象的单个属性以及整个值,如以下示例所示。spring-doc.cadn.net.cn

例 10.更新未包装对象的单个字段。
Update update = new Update().set("name.firstname", "Janet");
template.update(User.class).matching(where("id").is("Wasp"))
   .apply(update).first()
db.collection.update({
  "_id" : "Wasp"
},
{
  "$set" { "firstname" : "Janet" }
},
{ ... }
)
例 11.更新解包的对象。
Update update = new Update().set("name", new Name("Janet", "van Dyne"));
template.update(User.class).matching(where("id").is("Wasp"))
   .apply(update).first()
db.collection.update({
  "_id" : "Wasp"
},
{
  "$set" {
    "firstname" : "Janet",
    "lastname" : "van Dyne",
  }
},
{ ... }
)

对未打包的对象进行聚合

Aggregation Framework 将尝试映射类型化聚合的未包装值。 请确保在引用其值之一时使用包含包装器对象的属性路径。 除此之外,不需要执行任何特殊作。spring-doc.cadn.net.cn

未包装对象上的索引

可以将@Indexed注解添加到 unwrapped 类型的属性中,就像对常规对象所做的那样。 不能使用@Indexed以及@UnwrappedOwnershiping 属性上的注释。spring-doc.cadn.net.cn

public class User {

	@Id
    private String userId;

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

    // Invalid -> InvalidDataAccessApiUsageException
    @Indexed                          (2)
    @Unwrapped(onEmpty = USE_Empty)
    Address address;
}

public class UserName {

    private String firstname;

    @Indexed
    private String lastname;           (1)
}
1 索引lastnameusers收集。
2 无效@Indexed用法以及@Unwrapped

APP信息