Previous Next JavaScript must be enabled to correctly display this content

## Persistence Model

Learn about the schema of the persistence table and Spring Data Framework annotations.

An entity is a lightweight persistence domain object. The persistent state of an entity is represented through persistent fields using Java Beans / Plain Old Java Objects (POJOs).

The Spring Data Framework supports the persistence of entities to Oracle NoSQL Database tables. An entity is mapped to a table. The `ID` field in that entity is mapped to the primary key column of that table. All other fields in the entity are mapped to a JSON column of that table. Each instance of the entity will be stored as a single row in that table. The value of the `ID` field in that instance will be stored as the primary key value of that row. The values of all other fields (including other objects) (see JSON Column) in that instance will be serialized and stored as values in the JSON column of that row. Effectively, the table will always have only two columns: a primary key column and a JSON column.

Figure 1-2 Persistence Model

Description of "Figure 1-2 Persistence Model"

If a persistent POJO has a reference to another persistent POJO (nested objects) that maps to a different table, the Spring Data Framework will not serialize objects to multiple tables. Instead, all the nested objects will be serialized and stored as values in the JSON column. For more information about JSON Column mappings, see JSON Column.

The following is the syntax of an entity with `@NosqlTable` and `@NosqlId` annotations. In the following example, the `Student` class with the `@NosqlTable` annotation will be mapped to a table named `Student` in the Oracle NoSQL Database. The `ID` field with the `@NosqlId` annotation will be the primary key field in the `Student` table. The `firstName` and `lastName` fields will be mapped to a single JSON field named `kv_json_` in the `Student` table.

When retrieving entries from the repository the driver must instantiate the entity classes. These classes must have a default constructor or an empty constructor that is public or package protected.

Note:

The classes may have other constructors too.

    /*The @NosqlTable annotation specifies that
    this class will be mapped to an Oracle NoSQL Database table.*/
    @NosqlTable
    public class Student {
        //The @NosqlId annotation specifies that this field will act as the ID field.
        @NosqlId
        public long ID;

        public String firstName;
        public String lastName;

        public Student() {}
    }

Table Name

By default, the entity class name is used for the table name. You can provide a different table name using the `@NosqlTable` annotation. The `@NosqlTable` annotation enables you to define additional configuration parameters such as table name and timeout.

For example, an entity named `Student` will be persisted in a table named `Student`. If you want to persist an entity named `Student` in a table named `Learner`, you can achieve that using the `@NosqlTable` annotation.

If the `@NosqlTable` annotation is specified, then the following configuration can be provided.

Table 1-1 Attributes in NosqlTable Annotation

Parameter | Type | Ignored/ Optional/ Required in Oracle NoSQL Database | Ingnored/ Optional/ Required in Oracle NoSQL Database Cloud Service | Default | Description
--- | --- | --- | --- | --- | ---
`tableName` | `String` | Optional | Optional | empty | Specifies the name of the table, simple or namespace-qualified form. If empty, then the entity class name will be used. For more information about the namespace, see Namespace Management in the SQL Reference Guide. In the Oracle NoSQL Database Cloud Service, the namespace part, if provided, is used as the compartment name. For more information about using compartments, see Creating a Compartment in the Oracle NoSQL Database Cloud Service Guide.
`autoCreateTable` | `boolean` | Optional | Optional | `true` | Specifies if the table must be created if it does not exist. Note: The Spring Data Framework looks for the repositories used in the application in the `init` phase. If the table does not exist, and if the `@NosqlTable` annotation has the `autoCreateTable` as `true`, then the table will be created in the `init` phase.
`readUnits` | `int` | Ignored | Required | `-1` | Specifies the maximum read throughput to be used if the table is to be created. For more information about `readUnits`, see Plan your service in the Oracle NoSQL Database Cloud Service. Note: In Oracle NoSQL Database Cloud Service, you must set the `readUnits` parameter to a value greater than `0`. If you do not set the value, the Oracle NoSQL Database Cloud Service return an error.
`writeUnits` | `int` | Ignored | Required | `-1` | Specifies the maximum write throughput to be used if the table is to be created. For more information about `writeUnits`, see Plan your service in the Oracle NoSQL Database Cloud Service. Note: In Oracle NoSQL Database Cloud Service, you must set the `writeUnits` parameter to a value greater than `0`. If you do not set the value, the Oracle NoSQL Database Cloud Service will return an error.
`storageGB` | `int` | Ingored | Required | `-1` | Specifies the maximum amount of storage, in gigabytes, permitted for the table, if the table is to be created. For more information about `storageGB`, see Plan your service in the Oracle NoSQL Database Cloud Service. Note: In Oracle NoSQL Database Cloud Service, you must set the `storageGB` parameter to a value greater than `0`. If you do not set the value, the Oracle NoSQL Database Cloud Service will return an error.
`timeout` | `int` | Optional | Optional | `0` | Specifies the maximum time length, in milliseconds, that the operations are permitted to take before a timeout exception is thrown. If the value for `timeout` is not set then the timeout set in `NoSQLHandleConfig` class is used. For information about getting the timeout from `NoSQLHandleConfig` class using the `getTableRequestTimeout()` method, see NoSQLHandleConfig in the Java SDK API Reference. The `timeout` value can also be changed using `NosqlRepository.setTimeout(int)` method. For more information, see setTimeout in the SDK for Spring Data API Reference.
`consistency` | `String` | Optional | Optional | `EVENTUAL` | Specifies the consistency used for read operations. Valid values are based on `oracle.nosql.driver.Consistency` are `EVENTUAL` and `ABSOLUTE` . See Consistency in the Java SDK API Reference. Note: This is the default for all read operations. It can be overridden by using `NosqlRepository.setConsistency(String)`. For more information, see setConsistency in the SDK for Spring Data API Reference.
durability | String | Optional | Optional | `COMMIT_NO_SYNC` | Sets the default durability for all the write operations applied to this table. Valid values based on `oracle.nosql.driver.Durability` are `COMMIT_NO_SYNC, COMMIT_SYNC,` and `COMMIT_WRITE_NO_SYNC`. See Durability in the Java SDK API Reference.
capacityMode | NosqlCapacityMode For more information, see NosqlCapacityMode. | Optional | Optional | `NosqlCapacityMode.PROVISIONED` | Sets the capacity mode when the table is created. This applies only in cloud or cloud sim scenarios. A table is created with either `Provisioned Capacity` or `On-Demand Capacity`. For more details, see Cloud Concepts in the Oracle NoSQL Database Cloud Service. Set the values for the TableLimits instance based on the capacity mode as follows: Set `capacityMode` to PROVISIONED and all three `TableLimits`:`readUnits, writeUnits,` and `storageGB` to values greater than 0. Set `capacityMode` to ON_DEMAND and `storageGB` to a value greater than 0.
ttl | int | Optional | Optional | `0` | Sets the default table level Time to Live (TTL) when the table is created. The TTL enables the automatic expiration of table rows after the elapse of the specified duration. If the value is not set, the value `Constants.NOTSET_TABLE_TTL` is used, that is, table-level TTL is not applicable. See NOTSET_TABLE_TTL in the SDK for Spring Data API Reference. This parameter is applicable only when autoCreateTable is set to true.
ttlUnit | TtlUnit | Optional | Optional | `NosqlTable.TtlUnit.DAYS` | Sets the unit of TTL value. The valid values are: `NosqlTable.TtlUnit.DAYS` and `NosqlTable.TtlUnit.HOURS`. If the value is not set, the default value of days is used. This parameter is applicable only when autoCreateTable is set to true.

Primary Key

The table requires a primary key. The field named `ID` in the entity will be used as the primary key. You can select a different field in the entity (a field with a different name other than `ID`) to designate as the primary key using the `@NosqlId` annotation or the `@id` annotation.

When an `ID` field is mapped to a primary key column, the Spring Data Framework will automatically assign the corresponding data type to the ID field before storing it in the table. The following is a list of data type mappings between a Java type and an Oracle NoSQL Database type for the `ID` field.

The Java types that are provided in the following table are the only valid data types that can be used for a primary key.

Table 1-2 Mapping Between Java and Oracle NoSQL Database Types

Java Type | Oracle NoSQL Database Type
--- | ---
`java.lang.String` | `STRING`
`int` `java.lang.Integer` | `INTEGER`
`long` `java.lang.Long` | `LONG`
`double` `java.lang.Double` `float` `java.lang.Float` | `DOUBLE` Note: `double`, `java.lang.Double`, `float`, and `java.lang.Float` can be a primary key but it's not a valid `generated=true` type Note: Since `FLOAT` in Oracle NoSQL Database type is not explicitly used in NoSQL SDK for Java, the Java `float` and `java.lang.Float` are mapped to the `DOUBLE` type.
`java.math.BigDecimal` `java.math.BigInteger` | `NUMBER`
`boolean` `java.lang.Boolean` | `BOOLEAN`
`java.util.Date` `java.sql.Timestamp` `java.time.Instant` | `TIMESTAMP (P)`

The Spring Data Framework deduces the primary key using the following rules:

- `@NosqlId` annotation: If `@NosqlId` annotation is used on a field with a valid data type for the primary key, then that field is considered the primary key. If `@NosqlId` is used on a field of a type other than a valid data type for the primary key, an error is raised. For more information, see NosqlId in the SDK for Spring Data API Reference.
- `@org.springframework.data.annotation.Id` annotation: If `@org.springframework.data.annotation.Id` field annotation is used on a field with a valid data type for the primary key, then that field is considered as the primary key. If `@org.springframework.data.annotation.Id` is used on a field of a type other than a valid data type for the primary key, an error is raised.
- Not specified: If none of the preceding two annotations are specified, then the Spring Data Framework will use the field named `ID` as the primary key.

An error is raised if:

- No `@NosqlId` annotation or `@org.springframework.data.annotation.Id` annotation or `ID` field is found in the entity, as no primary key field can be inferred.
- Two or more of the `@NosqlId` or `@org.springframework.data.annotation.Id` annotated fields are used in the entity, as multiple primary key fields can be inferred.

Note:

The name of the fields that take the `@NosqlId` or `@org.springframework.data.annotation.Id` annotations must not be named `kv_json_`. This is because the data column of the table created by the Spring Data Framework will be named `kv_json_` and will be a JSON column where all attributes in the persistent entity that are not listed as primary key attributes will be stored.

The `@NosqlId` field annotation can take the following additional configuration:

Table 1-3 Attributes in NosqlId Annotation

Parameter | Type | Optional/Required | Default | Description
--- | --- | --- | --- | ---
`generated` | `boolean` | Optional | `false` | Specifies if the `ID` is autogenerated or not. If `true`, then it is defined as autogenerated by the program. If `int`/`Integer`, `long`/`Long`, `BigInteger` or `BigDecimal`, then `GENERATED ALWAYS as IDENTITY` is used. If `String`, then "String as UUID GENERATED BY DEFAULT" is used. If `false`, then the value must be managed by your application. Note: You can't autogenerate composite keys. Setting `@NosqlId.autoGenerated=true` leads to an error. You must manage the key values for all read/write calls when using the composite keys. If the key values are not set, the Oracle NoSQL Database generates an error.

Composite Primary Keys

Composite primary keys contain more than one primary key field. You can define a composite key class type to represent the composite keys.

A composite key class is a type that is mapped to multiple primary key fields of the entity class. A composite key class must be serializable and must define equals and hashcode methods. This class must consist of fields that are primitive data types.

Note:

The equality checks for the user-defined methods in the composite key class must be consistent with the equality checks performed in the Oracle NoSQL Database between the database types and their mapped keys.

You can use `@NosqlKe`y annotation to specify the components of a composite primary key in the composite key class.

Table 1-4 Attributes in the Nosqlkey Annotation

Parameter | Type | Optional/Required | Default | Description
--- | --- | --- | --- | ---
`shardKey` | `boolean` | `Optional` | `true` | Identifies if a primary key field is also a Shard Key. Shard keys affect the distribution of rows across shards. If `true`, the Spring Data Framework considers the primary key field as a part of the shard key. If `false`, the primary key field is not a part of the shard key. If you do not supply the `shardKey` parameter in the `Nosqlkey` annotation, the Spring Data Framework creates the primary key field as a shard key.
`order` | `int` | `Optional` | System determined | Specifies the ordering of the shard keys and non-shard keys within the primary key in a composite key class. You can set the `order` value based on the following rules, otherwise, the Spring Data Framework generates an error. The order of the shard keys must be less than the order of the non-shard primary key fields. The order must be specified for all the primary key fields or none. The Spring Data Framework does not support specifying the order for a partial list of primary key fields. The `order` value of each primary key field must be unique. If you do not specify the `order` parameter in the `Nosqlkey` annotation, the Spring Data Framework orders shard keys and non-shard keys individually in the alphabetic order of the field names. See Ordering the composite keys example.

For more details on `@NosqlKey` annotation, see NosqlKey in the SDK for Spring Data API Reference document.

Example: Ordering the composite keys

Consider primary key fields universityId, academicYear, and studentId defined in a composite key class.

You can define the `universityId` and `academicYear` fields to be a part of the shard key. The order values of these shard keys must be lesser than the `studentId` field, which is a non-shard key. You can use the following sample code to create a composite class.

    /* Define a composite Key class */

    public class StudentKey implements Serializable {

        @NosqlKey(shardKey = true, order = 1)
        long universityId;

        @NosqlKey(shardKey = true, order = 0)
        int academicYear;

        @NosqlKey(shardKey = false, order = 2)
        long studentId;

        /* public or package protected constructor required when retrieving from database */
        public StudentKey() {
        }
    }

In the preceding example, the `academicYear` field is considered as the first primary key field during the creation of the table.

The Spring Data Framework creates the table with the following DDL:

    /* Table DDL */

    CREATE TABLE IF NOT EXISTS Students (
       academicYear INTEGER,
       universityId LONG,
       studentId LONG,
       kv_json_ JSON,
       PRIMARY KEY(SHARD(academicYear, universityId), studentId)
    )

Consider a composite key class without specifying the `order` field.

    /* Define a composite Key class */

    public class StudentKey implements Serializable {

        @NosqlKey(shardKey = true)
        long universityId;

        @NosqlKey(shardKey = true)
        int academicYear;

        @NosqlKey(shardKey = false)
        long studentId;

        @NosqlKey(shardKey = false)
        long branchId;

        /* public or package protected constructor required when retrieving from database */
        public StudentKey() {
        }
    }

In the preceding example, the Spring Data Framework creates the shard keys and non-shard keys in the alphabetic order of the field names within the primary key. The table DDL is as follows:

    /* Table DDL */

    CREATE TABLE IF NOT EXISTS Students (
       academicYear INTEGER,
       universityId LONG,
       branchId LONG,
       studentId LONG,
       kv_json_ JSON,
       PRIMARY KEY(SHARD(academicYear, universityId), branchId, studentId)
    )

In the following cases, the Spring Data Framework considers all the primary key fields as shard keys and uses alphabetical ordering:

- If you declare the primary key fields in the composite key class without using the `@NosqlKey` annotation.
- If you declare the primary key fields in the composite key class without specifying the `shardKey` and the `order` values in the `@NosqlKey` annotation.

Note the following properties of the composite key class.

- You must have at least one field with `shardKey=true` in the composite key class, otherwise, the Spring Data Framework will generate an error.
- You can use a composite key class with repositories (as the `ID` type) and to represent an entity’s identity in a single object.
- You can annotate the fields as `@transient` to designate the nonpersistent state of the field.
- You can't nest composite key classes. This will generate an error.
- You can't autogenerate composite primary key fields. Setting `@NosqlId.autoGenerated=true` leads to an error. You must manage the key values for all read/write calls when using the composite keys. If the key values are not set, the Oracle NoSQL Database generates an error.

JSON Column

All other fields in the entity other than the primary key field will be converted into a NoSQL JSON value with the following rules:

- The Java scalar values will be converted to NoSQL JSON atomic values.
- The Java collections and array structures will be converted to a NoSQL JSON array.
- The Java nonscalar values will be recursively converted to NoSQL JSON objects.
- The Java null values will be converted to NoSQL JSON NULL values.
- The complex values will be converted to NoSQL JSON objects according to the following table.

Table 1-5 Mapping Between Java and NoSQL JSON Types

Java Type | Representation within Oracle NoSQL Database JSON data type
--- | ---
`java.lang.String` | `STRING`
`int` `java.lang.Integer` | `INTEGER`
`long` `java.lang.Long` | `LONG`
`double` `java.lang.Double` `float` `java.lang.Float` | `DOUBLE` Note: Since `FLOAT` in Oracle NoSQL Database type is not explicitly used in NoSQL SDK for Java, Java `float`, and `java.lang.Float` are mapped to the `DOUBLE` type.
`java.math.BigDecimal` `java.math.BigInteger` | `NUMBER`
`boolean` `java.lang.Boolean` | `BOOLEAN`
`byte[]` | `STRING` - a binary base64-encoded representation.
`java.util.Date` `java.sql.Timestamp` `java.time.Instant` | `STRING` - an ISO-8601 UTC time stamp encoded representation.
`org.springframework.data.geo.Point` | GeoJson Point For more information about GeoJson Data, see About GeoJson Data in the SQL Reference Guide.
`org.springframework.data.geo.Polygon` | GeoJson Polygon For more information about GeoJson Data, see About GeoJson Data in the SQL Reference Guide . Note: Polygons must conform to the following rules to be well-formed, otherwise they will be ignored when used in queries. A linear ring is a closed `LineString` with four or more positions. The first and last positions are equivalent, and they must contain identical values. A linear ring is either the boundary of a surface or the boundary of a hole in a surface. A linear ring must follow the right-hand rule for the area it bounds, that is, for exterior rings, their positions must be ordered counterclockwise, and for holes, their position must be ordered clockwise. Before inserting new polygons in the table, the `geo_is_geometry()` function can be used for verification. If polygon data is indexed an error will be raised if for some row the value of the index path is not valid, unless that value is NULL, json null, or EMPTY.
`java.util.ArrayList` `java.util.Collection` `java.util.List` `java.util.AbstractList` `java.util.HashSet` `java.util.Set` `java.util.AbstractSet` `java.util.TreeSet` `java.util.SortedSet` `java.util.NavigableSet` `java.util.Array []` | `ARRAY(JSON)` Note: A `java.util.ArrayList` object is instantiated for fields of type `java.util.Collection`, `java.util.List`, `java.util.AbstractList`, and `java.util.ArrayList`. A `java.util.HashSet` object is instantiated for fields of type `java.util.Set`, `java.util.AbstractSet`, and `java.util.HashSet`. A `java.util.TreeSet` object is instantiated for fields of type `java.util.SortedSet`, `java.util.NavigableSet`, and `java.util.TreeSet`.
`POJO<f1 T1, f2 T2...>` | `MAP(JSON)`
`java enum types` | `STRING`
`java.util.Map` `java.util.NavigableMap` `java.util.SortedMap` `java.util.HashMap` `java.util.LinkedHashMap` `java.util.Hashtable` `java.util.TreeMap` | MAP(JSON) Note: A `java.util.HashMap` is instantiated for fields of type `java.util.HashMap` A `java.util.LinkedHashMap` is instantiated for fields of type `java.util.Map` and `java.util.LinkedHasMap`. A `java.util.TreeMap` is instantiated for fields of type `java.util.NavigableMap`, `java.util.SortedMap`, and `java.util.TreeMap`.

Note:

Java data structures that contain cycles are neither supported nor detected. That is, if the entity object is traversed from the root down the fields and encounters the same object twice it becomes a cycle.