DATACASS-741 - Polishing.
Reflect impact of transient property usage in persistence constructor.
This commit is contained in:
@@ -1,30 +1,28 @@
|
||||
[[mapping.chapter]]
|
||||
= Mapping
|
||||
|
||||
Rich object mapping support is provided by the `MappingCassandraConverter`. `MappingCassandraConverter` has a
|
||||
rich metadata model that provides a complete feature set of functionality to map domain objects to CQL tables.
|
||||
Rich object mapping support is provided by the `MappingCassandraConverter`. `MappingCassandraConverter` has a rich metadata model that provides a complete feature set of functionality to map domain objects to CQL tables.
|
||||
|
||||
The mapping metadata model is populated by using annotations on your domain objects. However, the infrastructure
|
||||
is not limited to using annotations as the only source of metadata. The `MappingCassandraConverter` also lets you
|
||||
map domain objects to tables without providing any additional metadata, by following a set of conventions.
|
||||
The mapping metadata model is populated by using annotations on your domain objects.
|
||||
However, the infrastructure is not limited to using annotations as the only source of metadata.
|
||||
The `MappingCassandraConverter` also lets you map domain objects to tables without providing any additional metadata, by following a set of conventions.
|
||||
|
||||
In this chapter, we describe the features of the `MappingCassandraConverter`, how to use conventions for
|
||||
mapping domain objects to tables, and how to override those conventions with annotation-based mapping metadata.
|
||||
In this chapter, we describe the features of the `MappingCassandraConverter`, how to use conventions for mapping domain objects to tables, and how to override those conventions with annotation-based mapping metadata.
|
||||
|
||||
include::../{spring-data-commons-docs}/object-mapping.adoc[leveloffset=+1]
|
||||
|
||||
|
||||
[[mapping-conversion]]
|
||||
== Data Mapping and Type Conversion
|
||||
|
||||
This section explains how types are mapped to and from an Apache Cassandra representation.
|
||||
|
||||
Spring Data for Apache Cassandra supports several types that are provided by Apache Cassandra. In addition to
|
||||
these types, Spring Data for Apache Cassandra provides a set of built-in converters to map additional types.
|
||||
You can provide your own custom converters to adjust type conversion. See "`<<cassandra.mapping.explicit-converters>>`"
|
||||
for further details. The following table maps Spring Data types to Cassandra types:
|
||||
Spring Data for Apache Cassandra supports several types that are provided by Apache Cassandra.
|
||||
In addition to these types, Spring Data for Apache Cassandra provides a set of built-in converters to map additional types.
|
||||
You can provide your own custom converters to adjust type conversion.
|
||||
See "`<<cassandra.mapping.explicit-converters>>`" for further details.
|
||||
The following table maps Spring Data types to Cassandra types:
|
||||
|
||||
[cols="3,2", options="header"]
|
||||
[cols="3,2",options="header"]
|
||||
.Type
|
||||
|===
|
||||
| Type
|
||||
@@ -135,25 +133,22 @@ public enum Condition {
|
||||
[[mapping-conventions]]
|
||||
== Convention-based Mapping
|
||||
|
||||
`MappingCassandraConverter` uses a few conventions for mapping domain objects to CQL tables when no additional
|
||||
mapping metadata is provided. The conventions are:
|
||||
`MappingCassandraConverter` uses a few conventions for mapping domain objects to CQL tables when no additional mapping metadata is provided.
|
||||
The conventions are:
|
||||
|
||||
* The simple (short) Java class name is mapped to the table name by being changed to lower case.
|
||||
For example, `com.bigbank.SavingsAccount` maps to a table named `savingsaccount`.
|
||||
* The converter uses any registered Spring `Converter` instances to override the default mapping of object properties to
|
||||
tables fields.
|
||||
* The converter uses any registered Spring `Converter` instances to override the default mapping of object properties to tables fields.
|
||||
* The properties of an object are used to convert to and from properties in the table.
|
||||
|
||||
|
||||
[[mapping-configuration]]
|
||||
=== Mapping Configuration
|
||||
|
||||
Unless explicitly configured, an instance of `MappingCassandraConverter` is created by default when creating
|
||||
a `CassandraTemplate`. You can create your own instance of the `MappingCassandraConverter` to tell it
|
||||
where to scan the classpath at startup for your domain classes to extract metadata and construct indexes.
|
||||
Unless explicitly configured, an instance of `MappingCassandraConverter` is created by default when creating a `CassandraTemplate`.
|
||||
You can create your own instance of the `MappingCassandraConverter` to tell it where to scan the classpath at startup for your domain classes to extract metadata and construct indexes.
|
||||
|
||||
Also, by creating your own instance, you can register Spring `Converter` instances to use for mapping specific classes
|
||||
to and from the database. The following example configuration class sets up Cassandra mapping support:
|
||||
Also, by creating your own instance, you can register Spring `Converter` instances to use for mapping specific classes to and from the database.
|
||||
The following example configuration class sets up Cassandra mapping support:
|
||||
|
||||
.@Configuration class to configure Cassandra mapping support
|
||||
====
|
||||
@@ -164,23 +159,21 @@ include::../{example-root}/SchemaConfiguration.java[tags=class]
|
||||
====
|
||||
|
||||
`AbstractCassandraConfiguration` requires you to implement methods that define a keyspace.
|
||||
`AbstractCassandraConfiguration` also has a method named `getEntityBasePackages(…)`. You can override it
|
||||
to tell the converter where to scan for classes annotated with the `@Table` annotation.
|
||||
`AbstractCassandraConfiguration` also has a method named `getEntityBasePackages(…)`.
|
||||
You can override it to tell the converter where to scan for classes annotated with the `@Table` annotation.
|
||||
|
||||
You can add additional converters to the `MappingCassandraConverter` by overriding the `customConversions` method.
|
||||
|
||||
NOTE: `AbstractCassandraConfiguration` creates a `CassandraTemplate` instance and registers it with the container
|
||||
under the name of `cassandraTemplate`.
|
||||
|
||||
NOTE: `AbstractCassandraConfiguration` creates a `CassandraTemplate` instance and registers it with the container under the name of `cassandraTemplate`.
|
||||
|
||||
[[mapping.usage]]
|
||||
== Metadata-based Mapping
|
||||
|
||||
To take full advantage of the object mapping functionality inside the Spring Data for Apache Cassandra support,
|
||||
you should annotate your mapped domain objects with the `@Table` annotation. Doing so lets the classpath scanner find
|
||||
and pre-process your domain objects to extract the necessary metadata. Only annotated entities are used
|
||||
to perform schema actions. In the worst case, a `SchemaAction.RECREATE_DROP_UNUSED` operation drops your tables
|
||||
and you lose your data. The following example shows a simple domain object:
|
||||
To take full advantage of the object mapping functionality inside the Spring Data for Apache Cassandra support, you should annotate your mapped domain objects with the `@Table` annotation.
|
||||
Doing so lets the classpath scanner find and pre-process your domain objects to extract the necessary metadata.
|
||||
Only annotated entities are used to perform schema actions.
|
||||
In the worst case, a `SchemaAction.RECREATE_DROP_UNUSED` operation drops your tables and you lose your data.
|
||||
The following example shows a simple domain object:
|
||||
|
||||
.Example domain object
|
||||
====
|
||||
@@ -207,22 +200,21 @@ public class Person {
|
||||
IMPORTANT: The `@Id` annotation tells the mapper which property you want to use for the Cassandra primary key.
|
||||
Composite primary keys can require a slightly different data model.
|
||||
|
||||
|
||||
[[cassandra-template.id-handling]]
|
||||
=== Working with Primary Keys
|
||||
|
||||
Cassandra requires at least one partition key field for a CQL table. A table can additionally declare one or more
|
||||
clustering key fields. When your CQL table has a composite primary key, you must create a `@PrimaryKeyClass` to define
|
||||
the structure of the composite primary key. In this context, "`composite primary key`" means one or more partition columns
|
||||
optionally combined with one or more clustering columns.
|
||||
Cassandra requires at least one partition key field for a CQL table.
|
||||
A table can additionally declare one or more clustering key fields.
|
||||
When your CQL table has a composite primary key, you must create a `@PrimaryKeyClass` to define the structure of the composite primary key.
|
||||
In this context, "`composite primary key`" means one or more partition columns optionally combined with one or more clustering columns.
|
||||
|
||||
Primary keys can make use of any singular simple Cassandra type or mapped user-defined Type.
|
||||
Collection-typed primary keys are not supported.
|
||||
|
||||
==== Simple Primary Keys
|
||||
|
||||
A simple primary key consists of one partition key field within an entity class. Since it is one field only,
|
||||
we safely can assume it is a partition key.
|
||||
A simple primary key consists of one partition key field within an entity class.
|
||||
Since it is one field only, we safely can assume it is a partition key.
|
||||
The following listing shows a CQL table defined in Cassandra with a primary key of `user_id`:
|
||||
|
||||
.CQL Table defined in Cassandra
|
||||
@@ -261,8 +253,8 @@ public class LoginEvent {
|
||||
|
||||
==== Composite Keys
|
||||
|
||||
Composite primary keys (or compound keys) consist of more than one primary key field. That said, a composite primary key
|
||||
can consist of multiple partition keys, a partition key and a clustering key, or a multitude of primary key fields.
|
||||
Composite primary keys (or compound keys) consist of more than one primary key field.
|
||||
That said, a composite primary key can consist of multiple partition keys, a partition key and a clustering key, or a multitude of primary key fields.
|
||||
|
||||
Composite keys can be represented in two ways with Spring Data for Apache Cassandra:
|
||||
|
||||
@@ -290,9 +282,10 @@ CREATE TABLE login_event(
|
||||
|
||||
==== Flat Composite Primary Keys
|
||||
|
||||
Flat composite primary keys are embedded inside the entity as flat fields. Primary key fields are annotated with
|
||||
`@PrimaryKeyColumn`. Selection requires either a query to contain predicates
|
||||
for the individual fields or the use of `MapId`.
|
||||
Flat composite primary keys are embedded inside the entity as flat fields.
|
||||
Primary key fields are annotated with
|
||||
`@PrimaryKeyColumn`.
|
||||
Selection requires either a query to contain predicates for the individual fields or the use of `MapId`.
|
||||
The following example shows a class with a flat composite primary key:
|
||||
|
||||
.Using a flat composite primary key
|
||||
@@ -306,10 +299,10 @@ include::../{example-root}/LoginEvent.java[tags=class]
|
||||
==== Primary Key Class
|
||||
|
||||
A primary key class is a composite primary key class that is mapped to multiple fields or properties of the entity.
|
||||
It is annotated with `@PrimaryKeyClass` and must define `equals` and `hashCode` methods. The semantics of value equality
|
||||
for these methods should be consistent with the database equality for the database types to which the key is mapped.
|
||||
Primary key classes can be used with repositories (as the `Id` type) and to represent an entity's identity
|
||||
in a single complex object. The following example shows a composite primary key class:
|
||||
It is annotated with `@PrimaryKeyClass` and must define `equals` and `hashCode` methods.
|
||||
The semantics of value equality for these methods should be consistent with the database equality for the database types to which the key is mapped.
|
||||
Primary key classes can be used with repositories (as the `Id` type) and to represent an entity's identity in a single complex object.
|
||||
The following example shows a composite primary key class:
|
||||
|
||||
.Composite primary key class
|
||||
====
|
||||
@@ -349,19 +342,27 @@ An overview of the annotations follows:
|
||||
* `@Table`: Applied at the class level to indicate that this class is a candidate for mapping to the database.
|
||||
You can specify the name of the table where the object is stored.
|
||||
* `@PrimaryKey`: Similar to `@Id` but lets you specify the column name.
|
||||
* `@PrimaryKeyColumn`: Cassandra-specific annotation for primary key columns that lets you specify
|
||||
primary key column attributes, such as for clustered or partitioned. Can be used on single and multiple attributes
|
||||
to indicate either a single or a composite (compound) primary key. If used on a property within the entity, make sure to apply the `@Id` annotation as well.
|
||||
* `@PrimaryKeyColumn`: Cassandra-specific annotation for primary key columns that lets you specify primary key column attributes, such as for clustered or partitioned.
|
||||
Can be used on single and multiple attributes to indicate either a single or a composite (compound) primary key.
|
||||
If used on a property within the entity, make sure to apply the `@Id` annotation as well.
|
||||
* `@PrimaryKeyClass`: Applied at the class level to indicate that this class is a compound primary key class.
|
||||
Must be referenced with `@PrimaryKey` in the entity class.
|
||||
* `@Transient`: By default, all private fields are mapped to the row. This annotation excludes the field
|
||||
* `@Value`: This annotation is part of the Spring Framework . Within the mapping framework it can be applied to constructor arguments. This lets you use a Spring Expression Language statement to transform a key's value retrieved in the database before it is used to construct a domain object. In order to reference a property of a given `Row`/`UdtValue`/`TupleValue` one has to use expressions like: `@Value("#root.getString(0)")` where `root` refers to the root of the given document.
|
||||
* `@ReadOnlyProperty`: Applies at the field level to mark a property as read-only. Entity-bound insert and update statements do not include this property.
|
||||
where it is applied from being stored in the database.
|
||||
* `@Column`: Applied at the field level. Describes the column name as it is represented in the Cassandra table,
|
||||
thus letting the name differ from the field name of the class.
|
||||
* `@Indexed`: Applied at the field level. Describes the index to be created at session initialization.
|
||||
* `@SASI`: Applied at the field level. Allows SASI index creation during session initialization.
|
||||
* `@Transient`: By default, all private fields are mapped to the row.
|
||||
This annotation excludes the field where it is applied from being stored in the database.
|
||||
Transient properties cannot be used within a persistence constructor as the converter cannot materialize a value for the constructor argument.
|
||||
* `@PersistenceConstructor`: Marks a given constructor -- even a package protected one -- to use when instantiating the object from the database.
|
||||
Constructor arguments are mapped by name to the key values in the retrieved row.
|
||||
* `@Value`: This annotation is part of the Spring Framework . Within the mapping framework it can be applied to constructor arguments.
|
||||
This lets you use a Spring Expression Language statement to transform a key's value retrieved in the database before it is used to construct a domain object.
|
||||
In order to reference a property of a given `Row`/`UdtValue`/`TupleValue` one has to use expressions like: `@Value("#root.getString(0)")` where `root` refers to the root of the given document.
|
||||
* `@ReadOnlyProperty`: Applies at the field level to mark a property as read-only.
|
||||
Entity-bound insert and update statements do not include this property.
|
||||
* `@Column`: Applied at the field level.
|
||||
Describes the column name as it is represented in the Cassandra table, thus letting the name differ from the field name of the class.
|
||||
* `@Indexed`: Applied at the field level.
|
||||
Describes the index to be created at session initialization.
|
||||
* `@SASI`: Applied at the field level.
|
||||
Allows SASI index creation during session initialization.
|
||||
* `@CassandraType`: Applied at the field level to specify a Cassandra data type.
|
||||
Types are derived from the property declaration by default.
|
||||
* `@UserDefinedType`: Applied at the type level to specify a Cassandra User-defined Data Type (UDT).
|
||||
@@ -369,10 +370,10 @@ Types are derived from the declaration by default.
|
||||
* `@Tuple`: Applied at the type level to use a type as a mapped tuple.
|
||||
* `@Element`: Applied at the field level to specify element or field ordinals within a mapped tuple.
|
||||
Types are derived from the property declaration by default.
|
||||
* `@Version`: Applied at field level is used for optimistic locking and checked for modification on save operations. The initial value is `zero` which is bumped automatically on every update.
|
||||
* `@Version`: Applied at field level is used for optimistic locking and checked for modification on save operations.
|
||||
The initial value is `zero` which is bumped automatically on every update.
|
||||
|
||||
The mapping metadata infrastructure is defined in the separate, spring-data-commons project that is both
|
||||
technology- and data store-agnostic.
|
||||
The mapping metadata infrastructure is defined in the separate, spring-data-commons project that is both technology- and data store-agnostic.
|
||||
|
||||
The following example shows a more complex mapping:
|
||||
|
||||
@@ -410,15 +411,15 @@ include::../{example-root}/mapping/Coordinates.java[tags=class]
|
||||
[[mapping.index-creation]]
|
||||
==== Index Creation
|
||||
|
||||
You can annotate particular entity properties with `@Indexed` or `@SASI` if you wish to create secondary indexes
|
||||
on application startup. Index creation creates simple secondary indexes for scalar types, user-defined types,
|
||||
and collection types.
|
||||
You can annotate particular entity properties with `@Indexed` or `@SASI` if you wish to create secondary indexes on application startup.
|
||||
Index creation creates simple secondary indexes for scalar types, user-defined types, and collection types.
|
||||
|
||||
You can configure a SASI Index to apply an analyzer, such as `StandardAnalyzer` or `NonTokenizingAnalyzer` (by using
|
||||
`@StandardAnalyzed` and `@NonTokenizingAnalyzed`, respectively).
|
||||
|
||||
Map types distinguish between `ENTRY`, `KEYS`, and `VALUES` indexes. Index creation derives the index type
|
||||
from the annotated element. The following example shows a number of ways to create an index:
|
||||
Map types distinguish between `ENTRY`, `KEYS`, and `VALUES` indexes.
|
||||
Index creation derives the index type from the annotated element.
|
||||
The following example shows a number of ways to create an index:
|
||||
|
||||
.Variants of map indexing
|
||||
====
|
||||
@@ -435,9 +436,12 @@ include::./converters.adoc[]
|
||||
[[cassandra.mapping-usage.events]]
|
||||
== Lifecycle Events
|
||||
|
||||
The Cassandra mapping framework has several built-in `org.springframework.context.ApplicationEvent` events that your application can respond to by registering special beans in the `ApplicationContext`. Being based on Spring's application context event infrastructure lets other products, such as Spring Integration, easily receive these events as they are a well known eventing mechanism in Spring-based applications.
|
||||
The Cassandra mapping framework has several built-in `org.springframework.context.ApplicationEvent` events that your application can respond to by registering special beans in the `ApplicationContext`.
|
||||
Being based on Spring's application context event infrastructure lets other products, such as Spring Integration, easily receive these events as they are a well known eventing mechanism in Spring-based applications.
|
||||
|
||||
To intercept an object before it goes into the database, you can register a subclass of `org.springframework.data.cassandra.core.mapping.event.AbstractCassandraEventListener` that overrides the `onBeforeSave(…)` method. When the event is dispatched, your listener is called and passed the domain object (which is a Java entity). The following example uses the `onBeforeSave` method:
|
||||
To intercept an object before it goes into the database, you can register a subclass of `org.springframework.data.cassandra.core.mapping.event.AbstractCassandraEventListener` that overrides the `onBeforeSave(…)` method.
|
||||
When the event is dispatched, your listener is called and passed the domain object (which is a Java entity).
|
||||
The following example uses the `onBeforeSave` method:
|
||||
|
||||
====
|
||||
[source,java]
|
||||
@@ -457,7 +461,8 @@ The `AbstractCassandraEventListener` has the following callback methods:
|
||||
* `onAfterLoad`: Called in the `CassandraTemplate.select(…)`, `.slice(…)`, and `.stream(…)` methods after each row is retrieved from the database.
|
||||
* `onAfterConvert`: Called in the `CassandraTemplate.select(…)`, `.slice(…)`, and `.stream(…)` methods after converting a row retrieved from the database to a POJO.
|
||||
|
||||
NOTE: Lifecycle events are emitted only for root-level types. Complex types used as properties within an aggregate root are not subject to event publication.
|
||||
NOTE: Lifecycle events are emitted only for root-level types.
|
||||
Complex types used as properties within an aggregate root are not subject to event publication.
|
||||
|
||||
include::../{spring-data-commons-docs}/entity-callbacks.adoc[leveloffset=+1]
|
||||
include::./cassandra-entity-callbacks.adoc[leveloffset=+2]
|
||||
|
||||
Reference in New Issue
Block a user