NexJ Logo

Associated classes

This lesson introduces associated classes, which are attributes of one class that references another class. By completing this module, you will learn:

  • How classes can relate to each other through associations.
  • How to model those associations in NexJ Studio and use the reverse property to establish a two-way association.
  • How to use key indexes to capture those associations in the data store.

Create associated classes

Note

Before starting a new development task that makes changes to your model, verify that you have published the current model from the Model Library dialog. If you did not do this in the previous chapter or lesson, do so now.

In the previous lesson, you created a training:Entity class, which models the people and companies that your business has contact with. It contains a single attribute, lastName defined as a string. Simple attribute types, such as string, integer, timestamp, and decimal are collectively called primitive types. You often need more complex data, such as a mailing address, to be stored in an attribute. In this case, you can define the attribute to be based on another class in the business model. In this case, the attribute is referred to as a complex type or a complex attribute.

When you define a complex attribute, you establish an association between the classes that you are modeling. This association can be one-way, or two-way.

Reverse property

In a one-way association ClassA uses ClassB as an attribute, this allows access to instances of ClassB through instances of ClassA. However, ClassB instances have no way of directly accessing the ClassA instances that they are associated with. For example, if a class Person has a one way association to a class ContactInformation, then an instance of Person can access its related ContactInformation instances, but a given ContactInformation instance cannot access any information about the Person instances with which it is associated.

By contrast, if these classes have a two-way association, then both sets of class instances can access each other. The instances of the Person class can access related ContactInformation instances and the instances of the ContactInformation class can access their related Person instances, allowing you, for example, to find out who lives at an address or the owners of a given telephone number.

To specify a two-way association in NexJ Studio, you use the reverse property. This property is set on a complex attribute in order to identify how the class specified by the attribute refers back to the class containing the attribute.


In this lesson you expand the business model to include the ways in which a person or business can be contacted. You add two classes to the model: training:Telcom and training:TelcomType. training:Telcom models the different ways that an entity can be contacted. training:TelcomType models the different types of telecommunication channels available.

For example, Thing2 might have a home address and a business address. These would each be training:Telcom instances with a training:TelcomType of Address. However, Thing2 might also have a phone number, which would be a training:Telcom instance with a training:TelcomType of PhoneNumber. The training:Telcom class will have a two-way association with the training:TelcomType class and another one with the training:Entity class.

Create the training:Telcom and training:TelcomType classes. You create both classes right away so that in one class you can refer to the other class while defining the class's properties.

  1. In the Business Model layer, click the Classes tab.
  2. Right-click in the navigator and select New Class.
  3. Name the class training:TelcomType and click Finish.
  4. Right-click in the navigator again and select New Class.
  5. Name the class training:Telcom and click Finish

Specify the details of the training:TelcomType class. This class will have two attributes: name, a primitive type, and telcoms, a complex type that refers to the training:Telcom class.

  1. In the navigator, double-click the training:TelcomType class to open it.
  2. In the Overview tab, set the Caption property using a string resource, as you did with the Entity class. Set the en value to Telcom Type.
  3. In the Description field, enter Types of telcoms such as Home, Business, and Mobile.
  4. In the Aspects field, click the Select button and add LOCKING.
  5. In the Attributes tab, click the Add button to add two attributes to the class. Then set their properties as follows:

    Attribute descriptions for TelcomType

    AttributePropertyValueNotes
    name

    Typestring
    Requiredtrue
    Captionidsc.TelcomType.nameSet the caption on the Common tab. Use the selection tool to create this ID and give it an en value of Telcom name.
    telcoms


    Typetraining:TelcomThis is a complex type referring to the training:Telcom class.
    Collectiontrue
    Reversetypetype is the name of the corresponding attribute in the Telcoms class.
    CascadecancelSet the cascade property on the Validation tab.


    Property definitions:
    Collection
    Specifies that its attribute can hold multiple possible values. In the case of the training:TelcomType class, it indicates that for each instance of a training:TelcomType, there could be multiple different telecommunication channels (telcoms) of that type. For example, if there is a training:TelcomType instance of HomePhone, there can be multiple instances of telecommunication channels that are home phone numbers.
    Cascade
    Determines the deletion logic for the instances associated to the class through the attribute on which the property is set. In this case, setting it to cancel ensures that a training:TelcomType instance can only be deleted if there are no instances of the training:Telcom class associated with it. Other options are to delete the associated instances, or to clean the association between the instances.
    Reverse
    Establishes two-way associations between classes. In this case, setting the Reverse property on the telcoms enables you to access the training:Telcom instances related to a given training:TelcomType instance through the attribute relationship. In almost every case, the reverse property values will be reciprocal. That is, if ClassA:AttributeA has a reverse that points to ClassB:AttributeB, then ClassB:AttributeB will also have a reverse to ClassA:AttributeA. In this lesson, because the telcoms attribute has a reverse to Telcom:type, then when you define the training:Telcom class, its type attribute should have a reverse to TelcomType:telcoms.

  6. Save your changes.

Specify the details of the training:Telcom class. This class has five attributes, two of which are complex.

  1. In the navigator, double-click the training:Telcom class to open it.
  2. In the Overview tab, use the Select button to set the Caption property to a new string,idsc.TrainingTelcom.caption, with an en value of Telcom.
  3. In the Description field, enter a value of Telecommunications such as telephone number, email address, website address.
  4. In the Aspects field, click the Select button and add LOCKING.
  5. Add the following attributes with the specified properties to the training:Telcom class:

    Attributes to add to the Telcom class

    AttributePropertyValueNotes
    nameTypestring
    Requiredtrue
    addressTypestring
    Requiredtrue
    typeTypetraining:TelcomType
    RequiredtrueEnforces that every telecommunication channel must have an associated training:TelcomType.
    ReversetelcomsCompletes the reciprocal relationship by indicating that the telcoms attribute of the training:TelcomType class is itself of type training:Telcom, and has a reverse value of type.
    entityTypetraining:EntityAnother complex type, creating an association with the Entity class.
    RequiredtrueEvery Telecom channel must be associated with a entity specific Entity instance.
    ReversetelcomsLater. to complete the reciprocal relationship, you add the telcoms attribute of type training:Telcom to the Entity class.
    isPrimaryTypeboolean
    Initializer#fSet this property on the Value tab. #f is the Scheme symbol for “false”.
  6. Save your changes.

At this point you have completed setting up the association between the training:Telcom and the training:TelcomType classes. However, the training:Telcom class also has a two-way association with the training:Entity class, so you must update the training:Entity class as well to complete your work on the Business Model for this lesson.

Complete the relationship between the training:Telcoms and training:Entity classes:

  1. Open the training:Entity class.
  2. In the Attributes tab, add the following attribute and properties:

    Attribute to add to the Entity class

    AttributePropertyValueNotes
    telcomsTypetraining:Telcom
    Collectiontrue
    Reverseentity
    CascadedeleteSet the cascade property on the Validation tab.

    Info

    Setting the Cascade property to delete causes all the associated training:Telcom instances for a training:Entity instance to be deleted when the training:Entity instance is deleted.

  3. Click the Save button in the toolbar to save your changes.

Create a class diagram

Until this point you have modified your business model using editors to update the class properties and attributes. As your model becomes more complex, it is useful to use a visual method of exploring and editing the model. You can create UML class diagrams of your business model in NexJ Studio. You can then use the diagram to drill down into the model details and make model changes.

You can indicate an association in a type diagram in two ways:

  • Class with an attribute whose type is another class (e.g. + type : training:TelcomType).
  • Both classes are in the diagram, connected with a line labelled with the attribute or attributes by which the classes are associated, the cardinality of those attributes, and the direction of the association.

In this lesson you create a class diagram for your model and learn how to use it to access different classes in the model.

To create a class diagram for the training:Entity, training:Telcom, and training:TelcomType classes:

  1. In the Business Model layer, click the Diagrams tab.
  2. Right-click in the navigator and select New Class Diagram.
  3. Name the diagram training:Entity and click Finish. A blank canvas for the diagram appears.
    You can toggle the display of the grid using the menu items View → Grid.
  4. If the diagram palette is not shown, click on the small left-pointing arrow at the upper right of the diagram editor.
    The class diagram palette appears. It can be hidden by clicking the arrow again.
  5. With the newly created diagram open, click the Classes tab and drag the training:Entity class from the list into the empty canvas. A UML representation of the Entity class appears in the diagram. Note that the telcoms attribute is of type training:Telcom, indicating that it is an complex attribute. Note also that the brackets next to the telcoms attribute indicate that it is a collection of training:Telcom instances.
  6. Click the training:Telcom attribute and drag it to any open space in the diagram. The attribute disappears from the training:Entity class box and is replaced by an association line between the training:Entity class and the training:Telcom class.
    Note that there is a 0-to-many association on the telcoms indicating that each training:Entity can have any number of associated telecoms.
  7. Expand the diagram again by dragging the type attribute of the training:Telcom class to any open space in the diagram. Your diagram should now resemble the following picture:

    The training:Entity class has an attribute named telcoms of type training:Telcom. It is also a collection, meaning that one entity can have multiple (0..*) training:Telcom objects (home phone number, email address, mobile phone number, etc...). The training:Telcom class has an attribute named entity of type training:Entity. You created the two-way association path between these attributes by specifying the reverse property on each of them. In this case, the telecoms attribute on the training:Entity class has a reverse to the entity attribute on the training:Telcom class; the entity attribute on the training:Telcom class has a reverse to the telcoms attribute on the training:Entity class. Now, given a training:Telcom instance, you can access its associated training:Entity instance through the association path created by the reverse properties.
  8. To add a note to the diagram, click the Note button in the palette and then click in the upper-right hand corner of the diagram.
  9. Double-click the note to put it into edit mode, and enter Telcom Model - Fundamentals Course. Resize the note as appropriate.
  10. Save your work.
  11. Validate your model.

Test the model logic

Now you test the model logic to ensure it behaves as expected.

In the scratchpad, you create script that create an training:Entity instance, define a training:TelcomType instance, and then create a training:Telcom instance that has associations to both of them.

Note

The steps in this lesson assume that you have carried out the steps in Test your work, in the previous module which persists some data to the model. If you did not run those steps, or if you have subsequently carried out an action that erases the data store, such as using the Data Load Tool to reset or recreate the database, then you should rerun the code from that lesson in a console before proceeding.


  1. Use an existing or create a new scratchpad. (Resources → Scratchpads). Add the following commands to the scratchpad:

    ; read an entity that you created in the previous lesson and assign it to the
    ; variable "anEntity". read-instance is used here to find the Entity instance
    ; that has a lastName value of "Thing1"
    (define anEntity (read-instance training:Entity '() '(= lastName "Thing1") '()))
    
    ; ensure that Thing1 existed, if not create it
    (when (null? anEntity) (set! anEntity (training:Entity'new (: lastName "Thing1"))))
    
    ; create a new TelcomType of Home
    (define aTelcomType (training:TelcomType'new (: name "Home")))
    
    ; create a new Telcom instance associated with the Thing1 entity and the
    ; Home telcomtype
    (define aTelcom
       (training:Telcom'new
          (: entity anEntity)
          (: type aTelcomType)
          (: name (aTelcomType'name))
          (: address "(416) 555-1234")
       )
    )
  2. Run the Server Console using .

    Info

    The console automatically validates the model when it starts.


  3. Select the statements you entered in the scratchpad and press Ctrl+U to run them in the console. You should see output similar to the following:

    ; 12:16:17,507 DEBUG [SQLAdapter] select A.id, A.locking from NJEntity A where
     A.lastName = ?
    ; 12:16:17,508 DEBUG [SQLAdapter] Bind[0] = 'Thing1'
    ; 12:16:17,512 DEBUG [<default>] Activated
     SQLConnection@1317264939(pool=RelationalDatabaseConnectionPool(fragment=RelationalDatabaseFragment
     DefaultRelationalDatabase.<default>))
    ; 12:16:17,579 DEBUG [SQLAdapter] SQL execution time: 67 ms
    ; 12:16:17,580 DEBUG [SQLAdapter] Retrieved 1 instance(s) of Entity in 1 ms
    
    ; #<Instance<Entity, OID:1:V32:D2F82A01DE0A44FCB5807316DFCEB65F,
    CLEAN>(locking=0)>
    
    > ; 12:16:17,583 DEBUG [TelcomType] Invoking Event TelcomType.new(values)
    ; 12:16:17,588 DEBUG [GenericTransactionManager] Starting new transaction
     Tx(00000000000000005A1438C0B5F97552370ADC03C577DE56)
    ; 12:16:17,588 DEBUG [InvocationContext] Started new transaction
     Tx(00000000000000005A1438C0B5F97552370ADC03C577DE56)
    ; 12:16:17,589 DEBUG [<default>] Deactivating
     SQLConnection@1317264939(pool=RelationalDatabaseConnectionPool(fragment=RelationalDatabaseFragment
     DefaultRelationalDatabase.<default>))
    ; 12:16:17,591 DEBUG [TelcomType] Invoking Event TelcomType.create()
    
    ; #<Instance<TelcomType, null, NEW>(name="Home")>
    
    > ; 12:16:17,592 DEBUG [Telcom] Invoking Event Telcom.new(values)
    ; 12:16:17,595 DEBUG [Telcom] Invoking Event Telcom.create()
    
    ; #<Instance<Telcom, null, NEW>(name="Home", address="(416) 555-1234",
     type=Instance<TelcomType, null, NEW>, entity=Instance<Entity,
     OID:1:V32:D2F82A01DE0A44FCB5807316DFCEB65F, CLEAN>)>
    
    >

    Stop the Console by clicking the Terminate button .


Create the class persistence mapping

Now, use the Persistence Mapping tab to manage the persistence mapping of the class attributes to the data sources that you have defined.

Instead of using the navigator to access the class details, this time you use the class diagram.

To enable persistence for the Telcom class:

  1. Open the training:Entity class diagram (Business Model → Diagrams).
  2. Double-click the title of the training:Telcom class. The training:Telcom class opens in the editor.
  3. Click the Persistence Mapping tab.
  4. Set the Data Source property to DefaultRelationalDatabase.
  5. Set the Primary Table to TrainingTelcom.
  6. In the Key Generator field, select KeyGenerator.GUIDGen (GUID key generator).
  7. To define which attributes have their data stored in the database, click the Select Attribute Mappings button and select the following attributes:
    • name
    • address
    • type
    • entity
    • isPrimary
      The name, address, and isPrimary attributes appear in the Primitive Attributes list. The type and entity attributes appear in the Association Attributes list.
  8. To complete defining the associations between the training:Telcom class and the associated classes, set the Source Key, and Destination Key values for the Association Attributes according to the following table.

    Association attribute mapping for the Telcom class

    AttributeSource KeyDestination Key
    typeTrainingTelcom.FK_TelcomType
    entityTrainingTelcom.FK_Entity

    Leave the key blank if you are specifying the object key (AKA primary key)


    The type and entity attributes are complex, and associated with the training:TelcomType and training:Entity classes, respectively. For each of these, the source key indicates an index associated with the class being persisted, and the destination key indicates an index on the associated class. The values of the columns indexed by these keys will be coordinated to track the association of the class instances.

  9. Save your work.

  10. Click Update Data Source to apply these changes to the DefaultRelationalDatabase.

  11. Click OK on the Update Data Source window.

  12. You are taken to the properties of the DefaultRelationalDatabase in the Data Sources tab of the Persistence layer.

  13. On the General tab add Stores Telcom objects for an Entity. as the Description.

  14. Set the case insensitive flag for the id column to false.

Columns for the primitive attributes, including the id column used for the index have been created for you, as well as the primary key index. However, you need to add the columns and the indexes that are used to define the associations with other classes.

To create the columns and indexes to define the associations:

  1. In the Columns tab, click the last attribute, then click the Add button to add the following two columns:

    Column properties for the TrainingTelcom table

    Column NameTypeAllocationAllow NullsPrecisionCase Insensitive
    telcomTypeIdbinaryfixedfalse16false
    entityIdbinaryfixedfalse16false
  2. Deselect the Case Insensitive property of the id column.
  3. In the Indexes tab, add the following two indexes:

    Index properties for the Telcom table

    NameTypeUniqueIndex Columns
    TrainingTelcom.FK_TelcomTypebtreefalsetelcomTypeId
    TrainingTelcom.FK_EntitybtreefalseentityId

    Info

    The TrainingTelcom.FK_TelcomType index is used to instantiate the association between the training:Telcom and training:TelcomType classes through their respective type and telcoms attributes. Likewise, the TrainingTelcom.FK_entity index establishes the association between the training:Telcom and training:Entity classes. Foreign keys act by taking on values of the (usually primary) keys of other tables.

  4. Save your work.

Return to the training:Entity diagram so that you can enable persistence for the training:TelcomType class.

  1. Double-click the training:TelcomType class and select the Persistence Mapping tab.
  2. Select the DefaultRelationalDatabase as the Data Source.
  3. Set the Primary Table as TrainingTelcomType and specify the Key Generator of KeyGenerator.GUIDGen.
  4. Click the Select Attribute Mappings button  and add the name and telcoms attributes.
  5. Set the Name, Source Key, and Destination Key values for the telcoms attribute according to the following
    table.

    Association attribute mapping for the TelcomType class

    AttributeSource KeyDestination Key
    telcoms
    TrainingTelcom.FK_TelcomType
  6. Save your work.
  7. Click Update Data Source to apply these changes to the DefaultRelationalDatabase. Click OK on the Update Data Source window.
  8. You are taken to the properties of the DefaultRelationalDatabase in the Data Sources tab of the Persistence layer.
  9. In the General tab add Stores Telcom types. as the Description.
  10. In the Columns tab, deselect the Case Insensitive property of the id column.
  11. In the Indexes tab, add the following index:

    Index properties for the TelcomType table

    NameTypeUniqueIndex Columns
    TrainingTelcomType.OK_Namebtreetruename

    Info

    The TrainingTelcomType.OK_Name index ensures that all names in the class are unique. The acronym OK is used to signify "other key," i.e. a key that is neither the primary key nor a foreign key.

  12. Save your changes.

Return to the training:Entity diagram so that you can enable persistence mapping for the Entity class:

  1. In the training:Entity diagram, double-click the Entity class. The class opens in the editor.
  2. Click the Persistence Mapping tab.
  3. Click the Select Attribute Mappings button and add the telcoms attribute.
  4. Set the Source Key, and Destination Key values for the telcoms attribute according to the following table.

    Association attribute mapping for the Entity class

    AttributeSource KeyDestination Key
    telcoms
    TrainingTelcom.FK_Entity

    Note that the source key for the Entity:telcoms attribute was the destination key of the Telcom:entity attribute. Likewise, the source key of the Telcom:entity attribute is the destination key of Entity:telcoms.
    This completes the mapping required to instantiate the association between the Telcom and Entity classes.
    No changes to the data source are required.

  5. Save your work and validate the model.

Edit the upgrade file

Now that you have defined the logical database structure and the persistence model, make changes to the upgrade file so that you can upgrade your physical database and model dump file.

To update the upgrade file:

  1. In the Persistence layer on the Data Sources tab right-click the DefaultRelationalDatabase and select Generate Upgrade Steps.
  2. Leave the default values for Upgrade and Current Data Source.
  3. Select Old Model as the Old Data Source. You are going to use a published model as the old model.
  4. Select Published Model JAR and then click the browse button. Select the model you published at the end of the last lesson and click Next.
  5. Whenever you upgrade a database, you must increment the version number by a whole number. e.g. If the version retrieved from the published JAR file is 2.39; change the Version to 3.39.
  6. Enter the following as the Description: Added telcoms support.
  7. One the left side you can see a list of the upgrade steps that will be applied to the database. There are two CreateTable steps: one for the training:Telcom table and one for the training:TelcomType table. For each table, click the Columns and Indexes tabs to review how the tables will be created.
  8. Click Finish to create the upgrade steps.
  9. You must ensure that your current model's version matches the upgrade version. Click the Set current model button  in the toolbar to open the Model Library.
  10. With the current model selected, click Edit. Update the Model Version field to match the version associated with the upgrade you just created. So, if your upgrade is associated with version 3.39, then change the Model version to 3.39. This enables NexJ Studio to recognize that the model has been changed from the previous version so that your update can be applied to the supporting data stores.
  11. Click OK. Notice that the new version is now reflected in the table in the Models tab.
  12. Click the Save button  in the toolbar to save your work.

Publish the model

Publish the updated model from the Model Library.  This is important so that future lessons will know what the state of the data model was in the past.

  1. Click the Set current model button to open the Model Library.
  2. Select the training model.
  3. Click Publish. The Publish Model window opens.
  4. Select the folder that you want to publish your model to. The default value should be correct.
  5. Click Save. Click Close.
  6. The Console view lists the actions taking place as NexJ Studio publishes the model. If the publish is successful, you will see the message BUILD SUCCESSFUL.

    Info

    If the model contains any warnings or errors, you are prompted to confirm whether you want to continue publishing. For the purposes of this tutorial, it is OK to have warnings, but not errors, when you publish.

Upgrade the database

Use the Data Load Tool to apply the changes from the upgrade file to the physical database:

  1. Launch the Data Load Tool by clicking the drop-down arrow next to the Run tool button  in the toolbar.
  2. In the Model section, select Current.
  3. In the Server and Connection field, ensure that the Test option is cleared.
  4. In the Server field, select Development(development) (environment).
    You must select this environment because you need to use a user with permissions to change to the database table structure.
  5. In the Command field, select upgrade.
  6. In the Data Source field, select *.
  7. Select Ignore Upgradable Flag.
  8. Click Run. Confirm that you want to perform the upgrade action against a non-test connection.

To verify that the upgrade worked:

  1. Run your database's management tool or query client.
  2. Verify that the table NJTrainingTelcom exists with the proper column definitions in the training database:
    • For Microsoft SQL Server use the exec sp_help NJTrainingTelcom statement.

Test your work

Test your work by confirming that you can persist training:Telcom and training:TelcomType instances to the database.

To persist instances to the database:

  1. Start the Server Console in Debug mode.
  2. Open an existing or create a new scratchpad.
  3. Previously, you created classes in the Console that were not persisted. This time you use the (commit) command to save the data in the database.
    Add the following command to the end of the existing code :

    (commit)
  4. Select all the code and press Ctrl+U to run it.
  5. Inspect the console output, which should resemble the following:

    > (define anEntity (read-instance training:Entity '() '(= lastName "Thing1") '()));
     11:32:39,280 DEBUG [Entity] Invoking Event training:Entity.read(attributes, where,
     orderBy, count, offset, xlock)
    ; 11:32:39,280 DEBUG [GenericTransactionManager] Starting new transaction
     Tx(0100000000000000957F8007248ECAAF3255D10A83E37864)
    ; 11:32:39,280 DEBUG [InvocationContext] Started new transaction
     Tx(0100000000000000957F8007248ECAAF3255D10A83E37864)
    ; 11:32:39,280 DEBUG [SQLAdapter] select A.id, A.locking from NJTrainingEntity A where
     A.lastName = ?
    ; 11:32:39,280 DEBUG [SQLAdapter] Bind[0] = 'Thing1'
    ; 11:32:39,280 DEBUG [GenericConnectionManager] Activated
     connection SQLManagedConnection@18170911(user=sa,
     factory=SQLManagedConnectionFactory({serverName=localhost, maxStatements=0,
     lobBuffer=10485760, prepareSql=3, databaseName=test101b, appName=NexJ,
     bufferMaxMemory=65536, xaEmulation=true, sendStringParametersAsUnicode=true}))
    ; 11:32:39,312 DEBUG [SQLAdapter] SQL execution time: 32 ms
    ; 11:32:39,312 DEBUG [SQLAdapter] Retrieved 1 instance(s) of Entity in 0 ms
    
    ; #<Instance<training:Entity, OID:1:V32:A8D16D8698BB4AE092FB24462FF3BBC1,
     CLEAN>(locking=0)>
    
    > (define aTelcomType (training:TelcomType'new (: name "Home"))); 11:32:41,999 DEBUG
     [TelcomType] Invoking Event TelcomType.new(values)
    ; 11:32:41,999 DEBUG [training:TelcomType] Invoking Event training:TelcomType.create()
    
    ; #<Instance<training:TelcomType, null, NEW>(name="Home")>
    
    > (define aTelcom (training:Telcom'new (: entity anEntity) (: type aTelcomType) (: name
     (aTelcomType'name)) (: address "(416) 555-1234")))
    ; 11:32:44,952 DEBUG [training:Telcom] Invoking Event training:Telcom.new(values)
    ; 11:32:44,968 DEBUG [training:Telcom] Invoking Event training:Telcom.create()
    ; #<Instance<training:Telcom, null, NEW>(name="Home", address="(416) 555-1234",
     type=Instance<TelcomType, null, NEW>, entity=Instance<training:Entity,
     OID:1:V32:A8D16D8698BB4AE092FB24462FF3BBC1, CLEAN>)>
    
    > (commit) ; 11:32:47,202 DEBUG [training:TelcomType] Invoking Event
     training:TelcomType.commit()
    ; 11:32:47,202 DEBUG [training:Telcom] Invoking Event training:Telcom.commit()
    ; 11:32:47,202 DEBUG [training:TelcomType] Invoking Event training:TelcomType.load(attributes)
    ; 11:32:47,202 DEBUG [training:Telcom] Invoking Event training:Telcom.load(attributes)
    ; 11:32:47,202 DEBUG [training:Telcom] Invoking Event training:Telcom.load(attributes)
    ; 11:32:47,202 DEBUG [UnitOfWork] Committing 2 instance(s)
    ; 11:32:47,202 DEBUG [SQLAdapter] insert into NJTrainingTelcom(id, name, address,
     telcomTypeId, entityId, isPrimary, locking) values (?, ?, ?, ?, ?, ?, ?)
    ; 11:32:47,202 DEBUG [SQLAdapter] Bind[0] = 444882F001E3470EB297EF54E913351D
    ; 11:32:47,202 DEBUG [SQLAdapter] Bind[1] = 'Home'
    ; 11:32:47,202 DEBUG [SQLAdapter] Bind[2] = '(416) 555-1234'
    ; 11:32:47,202 DEBUG [SQLAdapter] Bind[3] = 1BB9C0FC578443A194BC68EC259A12DA
    ; 11:32:47,202 DEBUG [SQLAdapter] Bind[4] = A8D16D8698BB4AE092FB24462FF3BBC1
    ; 11:32:47,202 DEBUG [SQLAdapter] Bind[5] = 0
    ; 11:32:47,218 DEBUG [SQLAdapter] Bind[6] = 0
    ; 11:32:47,265 DEBUG [SQLAdapter] SQL execution time: 47 ms
    ; 11:32:47,265 DEBUG [SQLAdapter] insert into NJTrainingTelcomType(id, name, locking)
     values (?, ?, ?)
    ; 11:32:47,265 DEBUG [SQLAdapter] Bind[0] = 1BB9C0FC578443A194BC68EC259A12DA
    ; 11:32:47,265 DEBUG [SQLAdapter] Bind[1] = 'Home'
    ; 11:32:47,265 DEBUG [SQLAdapter] Bind[2] = 0
    ; 11:32:47,280 DEBUG [SQLAdapter] SQL execution time: 15 ms
    ; 11:32:47,280 DEBUG [InvocationContext] Committing transaction
     Tx(0100000000000000957F8007248ECAAF3255D10A83E37864)
    ; 11:32:47,280 DEBUG [GenericTransactionManager] Committing transaction
     Tx(0100000000000000957F8007248ECAAF3255D10A83E37864)
    ; 11:32:47,280 DEBUG [GenericConnectionManager] Deactivating
    connection SQLManagedConnection@18170911(user=sa,
    factory=SQLManagedConnectionFactory({serverName=localhost, maxStatements=0,
    lobBuffer=10485760, prepareSql=3, databaseName=test101b, appName=NexJ,
    bufferMaxMemory=65536, xaEmulation=true, sendStringParametersAsUnicode=true}))
    ; 11:32:47,280 DEBUG [UnitOfWork] Commit completed
    
    ; ()
  6. Verify that the data was correctly persisted by querying the database. Execute each of the following queries one by one:
    Microsoft SQL Server 

    select entityId, telcomTypeId, name from NJTrainingTelcom
    select id, lastName from NJTrainingEntity
    select id, name from NJTrainingTelcomType

    Info

    The entityId is a reference to the record id in the Entity table. Similarly, the telcomTypeId is a reference to the "Home" training:TelcomType record. This is where you see the Source Key and Destination Key properties in action.