Every schema defines an entity. The type of the entity is specified in
the valueType of the root node of the layer. An entity may have a
unique identifier. The unique identifier contains one or more
attributes. These attribute must not be included in array fields.
Below is a schema for a https://example.org/Person whose ID field is
https://example/org/Person/id:
{
"@context": "https://layeredschemas.org/ls.json",
"@id": "http://example.org/Person/schemaBase",
"@type": "Schema",
"valueType": "https://example.org/Person",
"layer": {
"@type": "Object",
"@id": "http://example.org/Person",
"entityIdFields": "https://example.org/Person/id",
"attributes": [
{
"@id": "http://example.org/Person/firstName",
"@type": "Value",
"attributeName":"firstName"
},
{
"@id": "http://example.org/Person/lastName",
"@type": "Value",
"attributeName": "lastName"
},
{
"@id": "http://example.org/Person/id",
"@type": "Value",
"attributeName": "id"
},
{
"@id": "http://example.org/Person/contact",
"@type": "Array",
"attributeName": "contact",
"arrayElements": {
"@type": "Reference",
"@id": "http://example.org/Person/contact/items",
"ref": "https://example.org/Contact"
}
}
]
}
}When a schema is compiled. the entity root nodes are marked with
https://lschema.org/entitySchema term that gives the schema ID for
the entity. The following graph shows the compiled schema for
https://example.org/Person entity. The root nodes for Person and
Contact entities are marked with https://lschema.org/entitySchema
annotation showing the schema for those entities. The Person entity
also declares the https://example.org/Person/id field as an entity
id. All the attributes under the Person root node up until the
Contact root node belong to the Person object. All the attributes
under the Contact root node belong to the Contact object.

When data elements are ingested, all nodes that are instances of
entity root nodes with nonempty entityIdFields annotation will have
the https://lschema.org/entityId field initialized to the entity
ID. If the entityIdFields is string value, then entityId will be
initialized to the content of that attribute. If entityIfFields is an
array, the entityId will be initialized as an array where every
element initialized from the value of the corresponding ID field.
A schema may specify the creation of additional links between ingested
entities. Consider the following entity named A:
{
"@context": "https://layeredschemas.org/ls.json",
"@id": "http://example.org/A/schema",
"@type": "Schema",
"valueType": "https://example.org/A",
"layer": {
"@type": "Object",
"@id": "http://example.org/A",
"entityIdFields": "http://example.org/A/id",
"attributes": {
"http://example.org/A/id": {
"@type": "Value",
"attributeName": "id"
}
}
}
}Here is another entity B that contains a foreign key containing the
identifier for an A entity:
{
"@context": "https://layeredschemas.org/ls.json",
"@id": "http://example.org/B/schema",
"@type": "Schema",
"valueType": "https://example.org/B",
"layer": {
"@type": "Object",
"@id": "http://example.org/B",
"attributes": {
"https://example.org/B/a_id": {
"@type": "Value",
"attributeName": "a_id"
}
}
}
}When instances of A and B are ingested, we would like to create a
link from the A instance to its B instance. The following addition
to the B schema does this:
{
"@context": "https://layeredschemas.org/ls.json",
"@id": "http://example.org/B/schema",
"@type": "Schema",
"valueType": "https://example.org/B",
"layer": {
"@type": "Object",
"@id": "http://example.org/B",
"attributes": {
"https://example.org/B/a_id": {
"@type": "Value",
"attributeName": "a_id"
},
"http://example.org/B/owner": {
"@type": "Reference",
"reference": "https://example.org/A/schema",
"fk": "https://example.org/B/a_id",
"link": "to",
"ingestAs": "edge",
"label": "owner",
"multi": false
}
}
}
}Here, the owner field defines a reference to A using its schema
ID. The other fields define how the link is constructed, and how the
A instance is found:
fk specifies the foreign key field contained in B that
contains the A entity id. If the A entity has multiple
identifiers, the fk field must specify an array of fields.link specifies the link direction. If to, the link is from A
to B. If from, the link is from B to A.ingestAs specifies how the link should be established. If
edge, an edge is added between the root node of B and the root
node of A. If node, a node is created for the owner field,
and that node is connected to the root node of A.label specifies the edge label. If omitted,
https://lschema.org/has is used.multi is true and there are multiple instances of A with the
given identifier, the B entity is linked to all those matching
A entities. If multi is false and multiple A entities match,
an error is returned.The resulting graph is:

An alternative method of linking uses foreign-key attributes directly. This form of linking entities is useful for database operations where the linked entity may not yet exist. This form stores the linking related annotations as part of the foreign key so they can later be used to conntect related objects in a database.
{
"@context": "https://layeredschemas.org/ls.json",
"@id": "http://example.org/B/schema",
"@type": "Schema",
"valueType": "https://example.org/B",
"layer": {
"@type": "Object",
"@id": "http://example.org/B",
"attributes": {
"https://example.org/B/a_id": {
"@type": "Value",
"attributeName": "a_id",
"reference": "https://example.org/A/schema",
"link": "to",
"linkNode": "https://example.org/B",
"label": "owner",
"multi": false
}
}
}
}In this form, the linking annotations are directly added to one of the
foreign-key attributes. A missing fk annotation means the attribute
itself is the foreign key. If the linked object has a composite key,
then one of the foreign key attributes can be used and a fk must be
specified to include all foreign key fields. The linkNode annotation
specifies the node that will be connected to the other entity, which
must be the schema node ID that must be one of the ancestors of the
foreign key node. In this example, the connection will be from the
entity root node of A to the entity root node of B.