Polishing.
Reorder API methods, remove unused MongoPersistentProperty.isNullable method, reduce visibility where possible. Add Javadoc and tweak documentation wording. Introduce DotPath utility to abstract dot path concatenation. See #2803. Original pull request: #896.
This commit is contained in:
@@ -1,6 +1,11 @@
|
||||
[[new-features]]
|
||||
= New & Noteworthy
|
||||
|
||||
[[new-features.3.2]]
|
||||
== What's New in Spring Data MongoDB 3.2
|
||||
|
||||
* Support for <<embedded-entities,Embedded Types>> to unwrap nested objects into the parent `Document`.
|
||||
|
||||
[[new-features.3.1]]
|
||||
== What's New in Spring Data MongoDB 3.1
|
||||
|
||||
|
||||
@@ -1,30 +1,33 @@
|
||||
[[embedded-entities]]
|
||||
== Embedded Types
|
||||
|
||||
Embedded entities are used to design value objects in your Java domain model whose properties are flattened out into the MongoDB Document.
|
||||
Embedded entities are used to design value objects in your Java domain model whose properties are flattened out into the parent's MongoDB Document.
|
||||
|
||||
[[embedded-entities.mapping]]
|
||||
=== Embedded Types Mapping
|
||||
|
||||
In the example below you see, that `User.name` is annotated with `@Embedded`.
|
||||
The consequence of this is that all properties of `UserName` are folded into the `user` document.
|
||||
Consider the following domain model where `User.name` is annotated with `@Embedded`.
|
||||
The `@Embedded` annotation signals that all properties of `UserName` should be unwrapped into the `user` document that owns the `name` property.
|
||||
|
||||
.Sample Code of embedding objects
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
public class User {
|
||||
class User {
|
||||
|
||||
@Id
|
||||
private String userId;
|
||||
@Id
|
||||
String userId;
|
||||
|
||||
@Embedded(onEmpty = USE_NULL) <1>
|
||||
UserName name;
|
||||
}
|
||||
|
||||
public class UserName {
|
||||
private String firstname;
|
||||
private String lastname;
|
||||
class UserName {
|
||||
|
||||
String firstname;
|
||||
|
||||
String lastname;
|
||||
|
||||
}
|
||||
----
|
||||
|
||||
@@ -41,37 +44,42 @@ By using `onEmpty=USE_EMPTY` an empty `UserName`, with potential `null` value fo
|
||||
====
|
||||
|
||||
For less verbose embeddable type declarations use `@Embedded.Nullable` and `@Embedded.Empty` instead `@Embedded(onEmpty = USE_NULL)` and `@Embedded(onEmpty = USE_EMPTY)`.
|
||||
Using those annotations simultaneously set JSR-305 `@javax.annotation.Nonnull` accordingly.
|
||||
Both annotations are meta-annotated with JSR-305 `@javax.annotation.Nonnull` to aid with nullability inspections.
|
||||
|
||||
[WARNING]
|
||||
====
|
||||
It is possible to use complex types within an embedded object.
|
||||
However those must not be, nor contain embedded fields themselves.
|
||||
However, those must not be, nor contain embedded fields themselves.
|
||||
====
|
||||
|
||||
[[embedded-entities.mapping.field-names]]
|
||||
=== Embedded Types field names
|
||||
|
||||
A value object can be embedded multiple times by using the optional `prefix` attribute of the `@Embedded` annotation.
|
||||
By dosing so the chosen prefix is prepended to each property or `@Field("...")` name in the embedded object.
|
||||
By dosing so the chosen prefix is prepended to each property or `@Field("…")` name in the embedded object.
|
||||
Please note that values will overwrite each other if multiple properties render to the same field name.
|
||||
|
||||
.Sample Code of embedded object with name prefix
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
public class User {
|
||||
class User {
|
||||
|
||||
@Id
|
||||
private String userId;
|
||||
@Id
|
||||
String userId;
|
||||
|
||||
@Embedded.Nullable(prefix = "u") <1>
|
||||
@Embedded.Nullable(prefix = "u_") <1>
|
||||
UserName name;
|
||||
|
||||
@Embedded.Nullable(prefix = "a_") <2>
|
||||
UserName name;
|
||||
}
|
||||
|
||||
public class UserName {
|
||||
private String firstname;
|
||||
private String lastname;
|
||||
class UserName {
|
||||
|
||||
String firstname;
|
||||
|
||||
String lastname;
|
||||
}
|
||||
----
|
||||
|
||||
@@ -79,11 +87,14 @@ public class UserName {
|
||||
----
|
||||
{
|
||||
"_id" : "a6a805bd-f95f",
|
||||
"ufirstname" : "Jean",
|
||||
"ulastname" : "Grey"
|
||||
"u_firstname" : "Jean", <1>
|
||||
"u_lastname" : "Grey",
|
||||
"a_firstname" : "Something", <2>
|
||||
"a_lastname" : "Else"
|
||||
}
|
||||
----
|
||||
<1> The prefix `u` is prepended to all properties of `UserName`.
|
||||
<1> All properties of `UserName` are prefixed with `u_`.
|
||||
<2> All properties of `UserName` are prefixed with `a_`.
|
||||
====
|
||||
|
||||
While combining the `@Field` annotation with `@Embedded` on the very same property does not make sense and therefore leads to an error.
|
||||
@@ -104,7 +115,7 @@ public class User {
|
||||
|
||||
public class UserName {
|
||||
|
||||
@Field("first-name") <2>
|
||||
@Field("first-name") <2>
|
||||
private String firstname;
|
||||
|
||||
@Field("last-name")
|
||||
@@ -116,18 +127,18 @@ public class UserName {
|
||||
----
|
||||
{
|
||||
"_id" : "2647f7b9-89da",
|
||||
"u-first-name" : "Barbara", <2>
|
||||
"u-first-name" : "Barbara", <2>
|
||||
"u-last-name" : "Gordon"
|
||||
}
|
||||
----
|
||||
<1> The prefix `u-` is prepended to all properties of `UserName`.
|
||||
<2> The field name is the result of the combination of the annotated field name an the chosen prefix.
|
||||
<1> All properties of `UserName` are prefixed with `u-`.
|
||||
<2> Final field names are a result of concatenating `@Embedded(prefix)` and `@Field(name)`.
|
||||
====
|
||||
|
||||
[[embedded-entities.queries]]
|
||||
=== Query on Embedded Objects
|
||||
|
||||
Defining queries on embedded properties is possible on type as well as field level as the provided `Critieria` is matched against the domain type.
|
||||
Defining queries on embedded properties is possible on type- as well as field-level as the provided `Criteria` is matched against the domain type.
|
||||
Prefixes and potential custom field names will be considered when rendering the actual query.
|
||||
Use the property name of the embedded object to match against all contained fields as shown in the sample below.
|
||||
|
||||
@@ -149,7 +160,7 @@ db.collection.find({
|
||||
----
|
||||
====
|
||||
|
||||
It is also possible to address any field of the embedded object directly via its property name as shown in the snippet below.
|
||||
It is also possible to address any field of the embedded object directly using its property name as shown in the snippet below.
|
||||
|
||||
.Query on field of embedded object
|
||||
====
|
||||
@@ -194,7 +205,7 @@ Though possible, using the embedded object itself as sort criteria includes all
|
||||
====
|
||||
|
||||
[[embedded-entities.queries.project]]
|
||||
==== Project on embedded object
|
||||
==== Field projection on embedded objects
|
||||
|
||||
Fields of embedded objects can be subject for projection either as a whole or via single fields as shown in the samples below.
|
||||
|
||||
@@ -203,7 +214,7 @@ Fields of embedded objects can be subject for projection either as a whole or vi
|
||||
[source,java]
|
||||
----
|
||||
Query findByUserLastName = query(where("name.firstname").is("Gamora"));
|
||||
findByUserLastName.fields().include("name"); <1>
|
||||
findByUserLastName.fields().include("name"); <1>
|
||||
List<User> user = template.findAll(findByUserName, User.class);
|
||||
----
|
||||
|
||||
@@ -225,7 +236,7 @@ db.collection.find({
|
||||
[source,java]
|
||||
----
|
||||
Query findByUserLastName = query(where("name.lastname").is("Smoak"));
|
||||
findByUserLastName.fields().include("name.firstname"); <1>
|
||||
findByUserLastName.fields().include("name.firstname"); <1>
|
||||
List<User> user = template.findAll(findByUserName, User.class);
|
||||
----
|
||||
|
||||
@@ -258,9 +269,9 @@ The `Repository` abstraction allows deriving queries on fields of embedded objec
|
||||
----
|
||||
interface UserRepository extends CrudRepository<User, String> {
|
||||
|
||||
List<User> findByName(UserName username); <1>
|
||||
List<User> findByName(UserName username); <1>
|
||||
|
||||
List<User> findByNameFirstname(String firstname); <1>
|
||||
List<User> findByNameFirstname(String firstname); <2>
|
||||
}
|
||||
----
|
||||
<1> Matches against all fields of the embedded object.
|
||||
@@ -330,14 +341,14 @@ db.collection.update({
|
||||
=== Aggregations on Embedded Objects
|
||||
|
||||
The <<mongo.aggregation,Aggregation Framework>> will attempt to map embedded values of typed aggregations.
|
||||
Please make sure to work with the properties path including the embedded wrapper object when referencing one of it's values.
|
||||
Please make sure to work with the property path including the embedded wrapper object when referencing one of its values.
|
||||
Other than that no special action is required.
|
||||
|
||||
[[embedded-entities.indexes]]
|
||||
=== Index on Embedded Objects
|
||||
|
||||
It is possible to attach the `@Indexed` annotation to properties of an embedded type just as it is done with regular objects.
|
||||
However it is not possible to use `@Indexed` along with the `@Embedded` annotation on the very same property of an object.
|
||||
It is not possible to use `@Indexed` along with the `@Embedded` annotation on the owning property.
|
||||
|
||||
====
|
||||
[source,java]
|
||||
@@ -348,9 +359,10 @@ public class User {
|
||||
private String userId;
|
||||
|
||||
@Embedded(onEmpty = USE_NULL)
|
||||
UserName name; <1>
|
||||
UserName name; <1>
|
||||
|
||||
@Indexed <2> // Invalid -> InvalidDataAccessApiUsageException
|
||||
// Invalid -> InvalidDataAccessApiUsageException
|
||||
@Indexed <2>
|
||||
@Embedded(onEmpty = USE_Empty)
|
||||
Address address;
|
||||
}
|
||||
@@ -360,7 +372,7 @@ public class UserName {
|
||||
private String firstname;
|
||||
|
||||
@Indexed
|
||||
private String lastname; <1>
|
||||
private String lastname; <1>
|
||||
}
|
||||
----
|
||||
<1> Index created for `lastname` in `users` collection.
|
||||
|
||||
Reference in New Issue
Block a user