Although OrientDB can work in schema-less mode, sometimes you need to enforce your data model using a schema. OrientDB supports schema-full or schema-hybrid solutions where the second one means to set such constraints only for certain fields and leave the user to add custom fields to the records. This mode is at class level, so you can have the "Employee" class as schema-full and "EmployeeInformation" class as schema-less.
NOTE: Changes to the schema are not transactional, so execute them outside a transaction.
To gain access to the schema APIs you need in the Schema instance of the database you're using.
OSchema schema = database.getMetadata().getSchema();
A Class is a concept taken from the Object Oriented paradigm. In OrientDB defines a type of record. It's the closest concept to a Relational DBMS Table. Class can be schema-less, schema-full or mixed.
A class can inherit from another shaping a tree of classes. [#Inheritance] means that the sub-class extends the parent one inheriting all the attributes as they was own.
Each class has its clusters that can be logical (by default) or physical. A class must have at least one cluster defined (as its default cluster), but can support multiple ones. In this case By default OrientDB will write new records in the default cluster, but reads will always involve all the defined clusters.
When you create a new class by default a new physical cluster is created with the same name of the class in lower-case.
Each class contains one or more properties. This mode is similar to the classic Relational DBMS approach where you define tables before storing records.
Example of creation of Account class. By default a new [Concepts#Physical_Cluster Physical Cluster] will be created to keep the class instances:
OClass account = database.getMetadata().getSchema().createClass("Account");
To create a new Vertex or Edge type you've to extend respectively the "V" and "E" classes. Example:
OClass person = database.getMetadata().getSchema().createClass("Account",
database.getMetadata().getSchema().getClass("V"));
Look at Graph Schema for more information.
To retrieve a persistent class use the getClass(String) method. If the class not exists NULL is returned.
OClass account = database.getMetadata().getSchema().getClass("Account");
To drop a persistent class use the OSchema.dropClass(String) method.
database.getMetadata().getSchema().dropClass("Account");
The records of the removed class will be not deleted unless you explicitly delete them before to drop the class. Example:
database.command( new OCommandSQL("DELETE FROM Account") ).execute();
database.getMetadata().getSchema().dropClass("Account");
To work in schema-full mode set the strict mode at class level by calling the setStrictMode(true)
method. In this case record of that class can't have not-defined properties.
Properties are the fields of the class. In this guide Property is synonym of Field.
Once the class has been created, you can define fields (properties). Below an example:
OClass account = database.getMetadata().getSchema().createClass("Account");
account.createProperty("id", OType.INTEGER);
account.createProperty("birthDate", OType.DATE);
Please note that each field must belong to one of Types.
To drop a persistent class property use the OClass.dropProperty(String)
method.
database.getMetadata().getSchema().getClass("Account").dropProperty("name");
The dropped property will not be removed from records unless you explicitly delete them using the [SQLUpdate SQL UPDATE + REMOVE statement]. Example:
database.getMetadata().getSchema().getClass("Account").dropProperty("name");
database.command(new OCommandSQL("UPDATE Account REMOVE name")).execute();
OrientDB supports two types of relationships: referenced and embedded.
OrientDB uses a direct link to the referenced record(s) without the need of costly JOINs of the Relational world. Example:
customer
Record A -------------> Record B
CLASS=Invoice CLASS=Customer
RID=5:23 RID=10:2
Record A will contain the reference to the Record B in the property called "customer". Note that both records are reachable by any other records since they have a [Concepts#RecordID RecordID].
1-1 and N-1 referenced relationships are expressed using the LINK type.
OClass customer= database.getMetadata().getSchema().createClass("Customer");
customer.createProperty("name", OType.STRING);
OClass invoice = database.getMetadata().getSchema().createClass("Invoice");
invoice.createProperty("id", OType.INTEGER);
invoice.createProperty("date", OType.DATE);
invoice.createProperty("customer", OType.LINK, customer);
In this case records of class "Invoice" will link to a record of class "Customer" using the field "customer".
1-N and N-M referenced relationships are expressed using the collection of links such as:
Example of a 1-N relationship between the classes Order and OrderItem:
OClass orderItem = db.getMetadata().getSchema().createClass("OrderItem");
orderItem.createProperty("id", OType.INTEGER);
orderItem.createProperty("animal", OType.LINK, animal);
OClass order = db.getMetadata().getSchema().createClass("Order");
order.createProperty("id", OType.INTEGER);
order.createProperty("date", OType.DATE);
order.createProperty("items", OType.LINKLIST, orderItem);
db.getMetadata().getSchema().save();
Embedded records, instead, are contained inside the record that embeds them. It's a kind of relationship stronger than the [#Referenced_relationships reference]. The embedded record will not have a own [Concepts#RecordID RecordID] since it can't be directly referenced by other records. It's only accessible via the container record. If the container record is deleted, then the embedded record will be deleted too. Example:
address
Record A <>----------> Record B
CLASS=Account CLASS=Address
RID=5:23 NO RID!
Record A will contain the entire Record B in the property called "address". Record B can be reached only by traversing the container record.
Example:
SELECT FROM account WHERE address.city = 'Rome'
1-1 and N-1 referenced relationships are expressed using the EMBEDDED type.
OClass address = database.getMetadata().getSchema().createClass("Address");
OClass account = database.getMetadata().getSchema().createClass("Account");
account.createProperty("id", OType.INTEGER);
account.createProperty("birthDate", OType.DATE);
account.createProperty("address", OType.EMBEDDED, address);
In this case, records of class "Account" will embed a record of class "Address".
1-N and N-M referenced relationships are expressed using the collection of links such as:
Example of a 1-N relationship between the class Order and OrderItem:
OClass orderItem = db.getMetadata().getSchema().createClass("OrderItem");
orderItem.createProperty("id", OType.INTEGER);
orderItem.createProperty("animal", OType.LINK, animal);
OClass order = db.getMetadata().getSchema().createClass("Order");
order.createProperty("id", OType.INTEGER);
order.createProperty("date", OType.DATE);
order.createProperty("items", OType.EMBEDDEDLIST, orderItem);
OrientDB supports a number of constrains for each field:
setMin()
setMax()
setMandatory()
setReadonly()
setNotNull()
Example:
profile.createProperty("nick", OType.STRING).setMin("3").setMax("30").setMandatory(true).setNotNull(true);
profile.createIndex("nickIdx", OClass.INDEX_TYPE.UNIQUE, "nick"); // Creates unique constraint
profile.createProperty("name", OType.STRING).setMin("3").setMax("30");
profile.createProperty("surname", OType.STRING).setMin("3").setMax("30");
profile.createProperty("registeredOn", OType.DATE).setMin("2010-01-01 00:00:00");
profile.createProperty("lastAccessOn", OType.DATE).setMin("2010-01-01 00:00:00");
To let to a property value to be UNIQUE use the UNIQUE index as constraint:
profile.createIndex("EmployeeId", OClass.INDEX_TYPE.UNIQUE, "id");
To let to a group of properties to be UNIQUE create a composite index made of multiple fields: Creation of composite index:
profile.createIndex("compositeIdx", OClass.INDEX_TYPE.NOTUNIQUE, "name", "surname");
For more information about indexes look at [Indexes Index guide].