ColdFusion 9.0 Resources |
Define RelationshipsRelationship is the most crucial aspect of ORM. In a relational database, relation between tables are defined using foreign key. However, in case of objects, relation between two objects is defined using association where one object has a reference to another. ORM defines how the object relation is mapped to the database relation. In this topic, relation and association would be used interchangeably. Before you learn how to define the mapping for relation, it is important to understand few key concepts:
To indicate that a property defines the relationship between two persistent components, as a result of relationship in the database table, specify the fieldtype in the cfproperty tag to one of the following:
Relationship attributesThis table specifies the attribute details for all the relationship types. The "Applies to" column indicates the relationship type that the attribute is applicable to; "all" indicates that the attribute is applicable to all relationship types.
Cascade optionsIn an association, it is cumbersome to apply an action performed on object to the other object. For example, in case of an Department-Employee one-to-many association, if you add an employee, the same change needs to be updated on the Department as well. The cascade option in Hibernate allows you to perform such operations. You can specify the following values in the cascade attribute:
Typically, cascade attribute is not used on a many-to-one or a many-to-many relationship. You can also specify comma separated cascade values in the cascade attribute. For a one-to-one or a one-to-many relationship, the most common values are all-delete-orphan. For an association where the child object can continue to exist even if the parent object is deleted, you can apply the save-update cascade value. Applying filter on associated objectsIn one-to-many and many-to-many relationships, an array or struct is retrieved. Filters can be applied to retrieve a subset of the associated objects. The filter can be specified in the where attribute, which is an SQL where clause. In a one-to-many association for artist and artwork: If you want to retrieve only the unsold artwork
for every Artist object, you need to define the mapping as follows:
<cfproperty name="unsoldArts" cfc="Art" fieldtype="one-to-many" fkcolumn="ARTISTID" where="issold=0"> InverseIn a bidirectional relationship, the inverse attribute is used on an association property to specify whether an SQL query should be executed for the association, when persisting the object. Consider the ART and ARTIST CFCs, which have a bidirectional one-to-many relationship. This means that each ART object has a reference to the ARTIST object and ARTIST object has a reference to the ART object. While persisting ARTIST and the associated ART, the relationship can be established in the database from both sides of the object. Setting inverse=true on one side of the relation tells ORM to ignore this side of relation for executing the SQL. As a general rule, in a bidirectional relation, one side must set inverse to true. For one-to-many or many-to-one relation, inverse should be set on the many side of the relation. For example, in ARTIST-ART relation, inverse should be set to true on the 'art' property in ARTIST. In many-to-many relation, you can set inverse=true on any side of the relation. One-to-one relationshipsA one-to-one relationship is where the source object has an attribute that references another single target object and vice-versa. An example of this relationship is the relationship between an employee and the assigned office cubicle, where one employee has one office cubicle and one office cubicle belongs to only one employee. A one-to-one relationship between two persistent components are defined using fieldtype value one-to-one. Syntax: <cfproperty name="fieldname" fieldtype="one-to-one" cfc="Referenced_CFC_Name" cascade="cascade_options" constrained="true|[false]" fetch="join|[select]" lazy="[true]|false"> There are two types of one-to-one relationships:
Primary key associationIn this type of association, the primary key of one table references to the primary key of another table. That is, both the tables share the same primary key. The following example shows how to define this mapping. ExampleConsider the EMPLOYEE and OFFICECUBICLE example. Both the tables share the same primary key. The mapping for these tables are as follows:
Unique foreign key associationIn this type of association, the foreign key of one table references the primary key of another table, and the foreign key column has a unique constraint. To define this relationship, fkcolumn attribute should be specified on the relationship-property of the CFC whose table contains the foreign key column. The other end of relation should use mappedby attribute. Syntax
<cfproperty name="fieldname" fieldtype="one-to-one" cfc="Referenced_CFC_Name" fkcolumn="foreign_key_column" mappedby="Mapped_Field_name_in_referenced_CFC" cascade="none" fetch="join|[select]" lazy="[true]|false"> Note: The mappedby attribute
can not be specified with the fkcolumn attribute.
ExampleIn the EMPLOYEE and OFFICECUBICLE example, OFFICECUBICLE has a foreign key column, EMPLOYEEID. This foreign key references the primary key of the Employee table. OFFICECUBICLE has an auto-generated primary key, which does not participate in the relationship. EMPLOYEE.cfc <cfcomponent persistent="true" table="Employee"> <cfproperty name="EmployeeID" fieldtype="id" generator="native"> <cfproperty name="firstname"> <cfproperty name="lastname"> <cfproperty name="officecubicle" fieldtype="one-to-one" cfc="officecubicle" mappedby="Employee"> </cfcomponent> OFFICECUBICLE.cfc <cfcomponent persistent="true" table="officecubicle"> <cfproperty name="id" fieldtype="id" generator="native"> <cfproperty name="Employee" fieldtype="one-to-one" cfc="Employee" fkcolumn="EmployeeID"> <cfproperty name="Location"> <cfproperty name="Size"> </cfcomponent>
In this case, OFFICECUBICLE entity has a independent Primary key which is auto-generated. One-to-many relationshipA one-to-many relationship is where the source object has field that stores a collection of target objects. These target objects may also have an inverse relationship back to the source object. This relationship is established by having a foreign key in the target table that maps to the primary key of the source table. An example of a one-to-many relationship is the relation between artist and art, where the artist has many artwork pieces. A one-to-many relationship between two persistent components is defined using the fieldtype value one-to-many in the cfproperty tag. The source object contains a collection of target objects. ColdFusion allows the collection to be one of the following types:
This collection is a persistence aware collection. Any addition or deletion from this collection is automatically persisted in the database. ArrayAn Artist object can contain the Art objects as an array. To define this mapping in the CFC, use the following syntax: Syntax <cfproperty name="field_name" fieldtype="one-to-many" cfc="Referenced_CFC_name" fkcolumn="Foreign_Key_column" type="array" orderby="order_by_string" cascade="cascade_options" lazy="[true]|false|extra" fetch="join|[select]" inverse="true|[false]" batchsize="N" optimisticlock="[true]|false" readonly="true|[false]"> For the artist-art example, the relationship property in Artist.cfc is defined as follows: <cfproperty name="art" type="array" fieldtype="one-to-many" cfc="Art" fkcolumn="ARTISTID">
StructAn Artist object can contain the Art objects as a struct. The key would be any column in the ART table (usually the primary key or a unique key). The value would be the Art object. To define this mapping, use the following syntax. Syntax <cfproperty name="field_name" fieldtype="one-to-many" cfc="Referenced_CFC_name" fkcolumn="Foreign_Key_column" type="struct" orderby="order_by_String" structkeycolumn = "Structure_Key_Column" structkeytype="ormtype" cascade="cascade_options" lazy="[true]|false|extra" fetch="join|[select]" inverse="true|[false]" batchsize="N" optimisticlock="[true]|false" readonly="true|[false]"> For the artist-art example, you can define the relationship property as: <cfproperty name="art" type="struct" fieldtype="one-to-many" cfc="Art" fkcolumn="ARTISTID" structkeytype="int" structkeycolumn="ArtID">
Many-to-one relationshipA many-to-one relationship is the inverse of a one-to-many relationship. In this relationship, many source objects can reference the same target object. An example of this relationship is the relation between Art and Artist, where many Art are created by the same Artist. This relationship is established with the foreign key in the source table that references the primary key in the target table. A many-to-one relationship between two persistent components is defined using the fieldtype value many-to-one in the cfproperty tag. Syntax<cfproperty name="fieldname" fieldtype="many-to-one" cfc="Referenced_CFC_Name" column="Foreign_Key_Column" mappedby="Mapped_Field_name_in_referenced_CFC" cascade="cascade_options" fetch="join|[select]" lazy="true|false" insert="[true]|false" update="[true]|false" optimisticlock="[true]|false" missingrowIgnored="true|[false]"> For the art-artist example, the relationship in the ART.cfc can be defined as: <cfproperty name="artist" fieldtype="many-to-one" fkcolumn="artistid" cfc="Artist"> fkcolumn="ARTISTID" indicates that the foreign key column in Art table references the primary key ARTISTID of ARTIST table. Many-to-many relationshipsA many-to-many relationship is where the source objects contain a collection of target objects and the target objects in turn contain a collection of source objects. An example of a many-to-many relationship is the relation between Order and Product, where an order has many products and a product has many orders. This relationship is established by using a third table called a 'LinkTable'. The LinkTable contains the foreign key to both the tables participating in the relation. ORM looks for the map key column in they LinkTable and not the target table. In the preceding example of Order-Product, a many-to-many relationship is established by using LinkTable. A many-to-many relationship between two persistent CFCs is defined using the fieldtype="many-to-many" value in the cfproperty tag. Note: If the fkcolumn name is not specified, ORM generates the fkcolumn
name in the "#relationName#_ID" format.
SyntaxOrder.cfc <cfproperty name="fieldname" fieldtype="many-to-many" cfc="fully qualified name" linktable="Link table name" linkcatalog="Catalog for the link table" linkschema="Schema for the link table" fkcolumn="Foreign Key column name" inversejoincolumn="Column name " mappedby="Property in the target component that is referenced by the fk column in join table" type="[array]|struct" orderby="order by String structkeycolumn="The structure key column name" structkeydatatype="datatype". cascade="cascade options" inverse="true|[false]" lazy = "[true]|false" [optional] fetch="join|[select]" [optional] batchsize="integer" optimisticlock="[true]|false" readonly="true|[false]" missingrowIgnored="true|[false]"> For the Order-Product example, the many-to-many relationship is established using a third table "OrderProduct" that has two foreign keys: OrderId and ProductId. OrderId references the primary key orderId in the order table, and ProductId references the primary key productId in the Product table. This relationship can be defined as follows:
|