First, create a MappingManager. It wraps an existing Session instance:
MappingManager manager = new MappingManager(session);
MappingManager
is thread-safe and can be safely shared throughout your application. You would typically create one instance at startup, right after your Session
.
Note that MappingManager
will initialize the Session
if not previously done (this was not the case in previous driver versions; if this is a problem for you, see MappingManager(session, protocolVersion)
).
Each entity class (annotated with @Table
) is managed by a dedicated Mapper object. You obtain this object from the MappingManager
:
Mapper<User> mapper = manager.mapper(User.class);
Mapper
objects are thread-safe. The manager caches them internally, so calling manager#mapper
more than once for the same class will return the previously generated mapper.
To save an object, use Mapper#save
:
UUID userId = ...; User u = new User(userId, "John Doe", new Address("street", 01000)); mapper.save(u);
To retrieve an object, use Mapper#get
:
UUID userId = ...; User u = mapper.get(userId);
get
's arguments must match the partition key components (number of arguments and their types).
To delete a row in a table, use Mapper#delete
. This method support deleting a row given either its primary keys, or the object to delete:
UUID userId = ...; mapper.delete(userId); mapper.delete(u);
All these CRUD operations are synchronous, but the Mapper
provides their asynchronous equivalents:
ListenableFuture<Void> saveFuture = mapper.saveAsync(u); ListenableFuture<User> userFuture = mapper.getAsync(userId); ListenableFuture<Void> deleteFuture = mapper.deleteAsync(userId);
The basic CRUD operations accept additional options to customize the underlying query:
ttl
: add a time-to-live value for the operation.timestamp
: add a timestamp value for the operation.consistencyLevel
: specify a consistency level.tracing
: set tracing flag for the query.saveNullFields
: if set to true, fields with value null
in an instance that is to be persisted will be explicitly written as null
in the query. If set to false, fields with null value won't be included in the write query (thus avoiding tombstones). If not specified, the default behavior is to persist null
fields.To use options, add them to the mapper call after regular parameters:
import static com.datastax.driver.mapping.Mapper.Option.*; mapper.save(new User(userId, "helloworld"), timestamp(123456L), tracing(true), ttl(42));
Some options don't apply to all operations:
Note that Option.consistencyLevel
is redundant with the consistency level defined by @Table. If both are defined, the option will take precedence over the annotation.
Default options can be defined for each type of operation:
mapper.setDefaultGetOption(tracing(true), consistencyLevel(QUORUM)); mapper.setDefaultSaveOption(saveNullFields(false)); mapper.setDefaultDeleteOption(consistencyLevel(ONE)); // Given the defaults above, this will use tracing(true), consistencyLevel(ONE) mapper.get(uuid, consistencyLevel(ONE));
To reset default options, use the following methods:
mapper.resetDefaultGetOption(); mapper.resetDefaultSaveOption(); mapper.resetDefaultDeleteOption();
Statement
sInstead of performing an operation directly, it's possible to ask the Mapper
to just return the corresponding Statement
object. This gives the client a chance to customize the statement before executing it.
Mapper.saveQuery(entity)
: returns a statement generated by the mapper to save entity
into the database.Mapper.getQuery(userId)
: returns a statement to select a row in the database, selected on the given userId
, and matching the mapped object structure.Mapper.deleteQuery(userID)
: returns a statement to delete a row in the database given the userId
provided. This method can also accept a mapped object instance.Mapper#map
provides a way to convert the results of a regular query:
ResultSet results = session.execute("SELECT * FROM user"); Result<User> users = mapper.map(results); for (User u : users) { System.out.println("User : " + u.getUserId()); }
This method will ignore:
ResultSet
that are not mapped for this entity.ResultSet
(setters won‘t be called so the value will be the one after invocation of the class’s default constructor).Result is similar to ResultSet
but for a given mapped class. It provides methods one()
, all()
, iterator()
, getExecutionInfo()
and isExhausted()
. Note that iterating the Result
will consume the ResultSet
, and vice-versa.
Accessor
s provide a way to map custom queries not supported by the default entity mappers.
To create an accessor, define a Java interface and annotate each method to provide the corresponding CQL query:
@Accessor public interface UserAccessor { @Query("SELECT * FROM user") Result<User> getAll(); }
The MappingManager
can then process this interface and automatically generate an implementation for it:
UserAccessor userAccessor = manager.createAccessor(UserAccessor.class); User user = userAccessor.getOne(uuid);
Like mappers, accessors are cached at the manager level and thus, are thread-safe/sharable.
A query can have bind markers, that will be set with the method's arguments.
With unnamed markers, the order of the arguments must match the order of the markers:
@Query("insert into user (id, name) values (?, ?)") ResultSet insert(UUID userId, String name);
With named markers, use @Param to indicate which parameter corresponds to which marker:
@Query("insert into user (userId, name) values (:u, :n)") ResultSet insert(@Param("u") UUID userId, @Param("n") String name);
If a method argument is a Java enumeration, it must be annotated with @Enumerated
to indicate how to convert it to a CQL type (the rules are the same as in mapping definition):
@Query("insert into user (key, gender) values (?,?)") ResultSet addUser(int key, @Enumerated(EnumType.ORDINAL) Enum value);
The declared return type of each method affects how the query will get executed:
Example:
@Query("SELECT * FROM user") public ListenableFuture<Result<User>> getAllAsync();
It is possible to customize query parameters to include in a Accessor
query with the annotation @QueryParameters. Then, options like consistency level, fetchsize or tracing are settable:
@Query("SELECT * FROM ks.users") @QueryParameters(consistency="QUORUM") public ListenableFuture<Result<User>> getAllAsync();