Projection - Operation Replace as Foreign Key
Overview
ReplaceAsForeignKey is a projection operation that creates a foreign key that references one of the source attributes. This operation receives a set of attributes as input and outputs a single foreign key attribute, which is specified on the replaceWith
property. A is.linkedEntity.identifier
trait is added to the resulting attribute. The argument of this trait has information about the source attribute that is referenced by this foreign key.
{
"traitReference": "is.linkedEntity.identifier",
"arguments": [
{
"entityReference": {
"entityShape": "entityGroupSet",
"constantValues": [
[
"<Path to entity>",
"<Attribute name>",
"<Relationship name>"
]
]
}
}
]
}
Note: you can access the API reference for this operation on this link.
Note: The foreign key attributes are used by the Object Model to calculate relationships.
Examples
The examples below refer to the Person
entity as defined here.
{
"entityName": "Person",
"hasAttributes": [
{
"name": "name",
"dataType": "string"
},
{
"name": "age",
"dataType": "integer"
},
{
"name": "address",
"dataType": "string"
},
{
"name": "phoneNumber",
"dataType": "string"
},
{
"name": "email",
"dataType": "string"
}
]
}
Using the ReplaceAsForeignKey operation on an entity attribute
If we have an entity attribute, we can use ReplaceAsForeignKey to create a foreign key attribute.
{
"name": "PersonInfo",
"entity": {
"source": "Person",
"operations": [
{
"$type": "replaceAsForeignKey",
"reference": "name",
"replaceWith": {
"name": "personFK",
"dataType": "entityId"
}
}
]
}
}
The resulting resolved PersonInfo entity typed attribute is:
PersonInfo |
---|
personFK |
The is.linkedEntity.identifier
trait on the personFK
attribute looks like the following:
{
"traitReference": "is.linkedEntity.identifier",
"arguments": [
{
"entityReference": {
"entityShape": "entityGroupSet",
"constantValues": [
[
"Person.cdm.json/Person",
"name",
"PersonInfo_Person"
]
]
}
}
]
}
Using the ReplaceAsForeignKey operation when extending an entity
If we have an entity that extends another entity, we can use ReplaceAsForeignKey to create a foreign key attribute.
Given an entity, Child, that extends from the Person entity:
{
"entityName": "Child",
"extendsEntity": {
"source": "Person",
"operations": [
{
"$type": "replaceAsForeignKey",
"reference": "name",
"replaceWith": {
"name": "personFK",
"dataType": "entityId"
}
}
]
},
"hasAttributes": []
}
The resulting resolved Child entity is:
Child |
---|
personFK |
Using the ReplaceAsForeignKey operation to create a multi part foreign key
On the examples above, the foreign keys created are identified by one attribute only. In some cases one attribute alone is not capable of uniquely identifying a relationship, for example there might be multiple people with the same name. For these cases, we can create a relationship that is composed by multiple attributes as below.
{
"name": "PersonInfo",
"entity": {
"source": "Person",
"operations": [
{
"$type": "replaceAsForeignKey",
"reference": "name",
"replaceWith": {
"name": "nameFK",
"dataType": "entityId"
}
},
{
"$type": "replaceAsForeignKey",
"reference": "address",
"replaceWith": {
"name": "addressFK",
"dataType": "entityId"
}
}
]
}
}
The resulting resolved PersonInfo entity typed attribute is:
PersonInfo |
---|
nameFK |
addressFK |
Let us have a look at the is.linkedEntity.identifier
trait on both these resulting attributes.
First nameFK
:
{
"traitReference": "is.linkedEntity.identifier",
"arguments": [
{
"entityReference": {
"entityShape": "entityGroupSet",
"constantValues": [
[
"Person.cdm.json/Person",
"name",
"PersonInfo_Person"
]
]
}
}
]
}
Now addressFK
:
{
"traitReference": "is.linkedEntity.identifier",
"arguments": [
{
"entityReference": {
"entityShape": "entityGroupSet",
"constantValues": [
[
"Person.cdm.json/Person",
"address",
"PersonInfo_Person"
]
]
}
}
]
}
By looking at the two traits above, you can see that both the relationship names are the same PersonInfo_Person
. This is an indicator that these attributes combined make up the relationship foreign key.
Using the ReplaceAsForeignKey operation to create a polymorphic relationship
For this example, we will use another entity called ContactKinds
that has three entity attributes pointing to Email
, Phone
and Social
.
{
"entityName": "ContactKinds",
"hasAttributes": [
{
"name": "emailKind",
"entity": "Email"
},
{
"name": "phoneKind",
"entity": "Phone"
},
{
"name": "socialKind",
"entity": "Social"
}
]
}
Phone | Social | |
---|---|---|
emailId | phoneId | socialId |
address | number | account |
isPrimary | isPrimary | isPrimary |
This entity defines three different methods that a customer can be contact at. We want to create an entity attribute that is a foreign key to one of email, phone or social. To achieve this goal, we will use the ReplaceAsForeignKey along with CombineAttributes. Note that because ContactKinds
is a polymorphic entity we need to set the isPolymorphicSource
property to true.
{
"name": "ContactAt",
"isPolymorphicSource": true,
"entity": {
"source": "ContactKinds",
"runSequentially": true,
"operations": [
{
"$type": "combineAttributes",
"select": [ "emailId", "phoneId", "socialId" ],
"mergeInto": {
"name": "contactAtId",
"dataType": "entityId"
}
},
{
"$type": "replaceAsForeignKey",
"reference": "contactAtId",
"replaceWith": {
"name": "contactAtFK",
"dataType": "entityId"
}
},
{
"$type": "addTypeAttribute",
"typeAttribute": {
"name": "contactAtType",
"dataType": "integer"
}
}
]
}
}
The resulting resolved ContactAt entity typed attribute is:
ContactAt |
---|
contactAtFK |
contactAtType |
NOTE: in this case the attribute, contactAtFK
holds a foreign key to email, phone or social. We also used a AddTypeAttribute operation to create an attribute that is used to specify which entity contactAtFK
is pointing to per-record. Adding the type attribute is not required, but useful.