NexJ Logo

Associated classes

Learning objectives

In this learning module, you will be introduced to associated classes which are attributes of one class that reference 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.

Key concepts

  • Primitive types - Simple attribute types, such as string, integer, timestamp, and decimal.
  • Complex attribute - Attribute based on another class in the business model.
  • Reverse property -  Set on a complex attribute in order to identify how the class specified by the attribute refers back to the class containing the attribute.


Creating associated classes

In the previous lesson, Persisted classes, 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. 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, 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.

In a one-way association, ClassA uses ClassB as an attribute, allowing access to instances of ClassB through instances of ClassA. However, ClassB instances have no way of directly accessing the ClassA instances with which they are associated. For example, if a class Person has a one-way association to a class ContactInformation, 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, 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 can use the reverse property.

In this lesson you will expand the business model to include the ways in which a person or business can be contacted. You will 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.

Learning activity

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

  1. Open the training:Fundamentals class diagram from the Busuness Model/Diagrams layer.
  2. Right-click in the diagram and select New > Class.
  3. Name the class training:TelcomType and click Finish.
  4. Right-click in the diagram again and select New > Class.
  5. Name the class training:Telcom and click Finish

You should see something like the following diagram.

Right mouse click on the title of training:Entity and "Unhide Derivation > training:Locking"

In the top, right corner of the diagram editor, expose the palette  and select the Note item. Place a note in the top left corner of your diagram and enter "Fundamentals Training Business Model" and the date. Drag and drop the classes so your diagram looks something like the following:

Adding the primitive attributes

Right mouse click and select Create Attribute on the training:Telcom class then the training:TelcomType class and add the following attributes.

Adding the association attributes

Right mouse click on the training:Telcom class and select Create Association... Fill the resulting dialog out as follows and press OK.

Right mouse click training:Telcom and select Create Association again. This time fill the Create Association dialog as follows and press OK.

Your diagram should now look something like...


Creating without the diagram

Of course, creating the model visually is just an option. You can create the classes as well in the Classes tab of the Business Model layer. If you didn't use the diagram editor, you would do something like...

  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
  6. Then you would set all of the properties of the class using the Overview and Attributes tab as follows.

Open the class editor for the training:TelcomType class. If your in the diagram editor, you can get to the class editor by double-clicking on the class. From the work we've already done in the diagram editor, the class should have two attributes: name, a primitive type, and telcoms, a complex type that refers to the training:Telcom class. There are a couple of other settings we will want to add to the class.

  1. In the navigator or diagram editor, 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 training:Entity class. Set the en value to Telcom Type.  and call the string idsc.training.telcomType.
  3. In the Description field, enter Types of telcoms such as Home, Business, and Mobile.
  4. In the Aspects field, click the Select button Select button and add training:LOCKING.
  5. In the Attributes tab, you should see two attributes - name and telcoms. Complete the properties as follows. Things that you will need to add are highlighted in yellow.

    Attribute descriptions for TelcomType

    AttributePropertyValueNotes
    name

    Typestring
    Requiredtrue
    Caption

    idsc.training.telcomType.name

    Set 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. 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, when you define the training:Telcom class, its type attribute should have a reverse to TelcomType:telcoms.

  6. Save your changes.

Open the class editor for the training:Telcom class. This class has five attributes, two of which are complex.

  1. In the navigator or diagram editor, 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.training.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 training:LOCKING.
  5. You should see the following attributes with the specified properties on the training:Telcom class. Complete the properties as follows. Things that you will need to add are highlighted in yellow.

    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 an entity-specific Entity instance.
    ReversetelcomsLater, to complete the reciprocal relationship, add the telcoms attribute of type training:Telcom to the Entity class.
    isPrimaryTypeboolean
    Initializer

    #f

    Set this property on the Value tab. #f is the Scheme symbol for “false”. If you set the language to "js" for the initializer script's properties, then simply use 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, ensure the telcoms attribute has the following properties set:

    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.

Update the class diagram

As you've seen, 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. If you then add attributes, derivations, or descriptions, to classes, they aren't automatically added to existing diagrams. In this section, we want to update the diagram to end up looking like the image below.


Associations in class diagrams

You can see 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.
  1. The only thing missing from the diagram are the training:LOCKING aspects that we added to the training:Telcom and training:TelcomType classes.
  2. Right mouse click on each class and select "Unhide Derivations" to expose the aspects we added.
  3. You could also unhide the descriptions for the classes if you want. Your diagram should then look something like...

  1. Save your work.
  2. Validate your model.

Test the model logic

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

In a scratchpad, we will create a 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")
       )
    )
    Javascript
    ; If you are running your console in javascript with the read -Dnexj.repl.language="js" flag, then use the following script
    ; 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"
    ; notice that any non-standard javascript syntax (like "-" and ":" in identifiers) is quoted with #"<expression>"
    var anEntity = #"read-instance"(#"training:Entity", null, #"'()", null);
    
    ; ensure that Thing1 existed, if not create it
    if (null?(anEntity)) {
     anEntity = new #"training:Entity"({lastName: "Thing1"});
    }
    
    ; create a new TelcomType of Home
    var aTelcomType = new #"training:TelcomType"({name: "Home"});
    
    ; create a new Telcom instance associated with the Thing1 entity and the
    ; Home telcomtype
    var aTelcom = new #"training:Telcom"({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 of the class attributes to the data sources that you have defined.

To enable persistence for the Telcom class:

  1. Open the training:Fundamentals 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 at the bottom of the editor.
  4. Set the Data Source property to training:DB.
  5. Set the Primary Table to Telcom.

    Datasource Prefix

    Because the training:DB datasource has a prefix of "TRN" (set on the datasource editor's advanced tab), the actual physical table will be TRNTelcom.

  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
    typeTelcom.FK_TelcomType
    entityTelcom.FK_Entity

    Leave the key blank if you are specifying the object key for the source or destination (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 is a foreign-key index on the class you are working with, and the destination key is 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 training:DB datasource.

  11. Click OK on the Update Data Source window.

  12. You are taken to the properties of the training:DB datasource 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 for 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 Telcom table

    Column NameTypeAllocationAllow NullsPrecisionCase Insensitive
    telcomTypeIdbinaryfixedfalse16false
    entityIdbinaryfixedfalse16false
  2. In the Indexes tab, add the following two indexes:

    Index properties for the Telcom table

    NameTypeUniqueIndex Columns (press  add in lower list)
    Telcom.FK_TelcomTypebtreefalsetelcomTypeId
    Telcom.FK_EntitybtreefalseentityId

    Info

    The Telcom.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 Telcom.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.

  3. Save your work.

Return to the training:Fundamentals 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 training:DB datasource.
  3. Set the Primary Table as TelcomType 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
    Telcom.FK_TelcomType
  6. Save your work.
  7. Click Update Data Source to apply these changes to the training:DB datasource. 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
    TelcomType.OK_Namebtreetruename

    Info

    The TelcomType.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:Fundamentals 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
    Telcom.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.

  1. In the Persistence layer on the Data Sources tab right-click the training:DB and select Generate Upgrade Steps.
  2. Leave the default values for Upgrade and Current Data Source.
  3. Select Local History as the Old Data Source. You are going to use a published model as the old model.
  4. Select Revision Time from before you added the TelcomType and Telcom tables and click Next.
  5. Whenever you upgrade a database, you must increment the version number by a whole number. e.g. 3.1092.1307.167.53 to 4.1092.1307.167.53.
  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 4.1092.1307.167.53, then change the Model version to 4.1092.1307.167.53. This enables the upgrade tool to recognize that the model has changed so that your update can be applied to existing 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.

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.properties) 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.
  9. You should get an Exit code = 0 as follows:

To verify that the upgrade worked:

  1. Run your database's management tool or query client.
  2. Verify that the table TRNTelcom exists with the proper column definitions in the training database:
    • For Microsoft SQL Server use the
      use training;
      exec sp_help TRNTelcom;
      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 from earlier in the lesson :

    (commit) ; or commit() for javascript
  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 TRNEntity 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 TRNTelcom(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 TRNTelcomType(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 TRNTelcom
    select id, lastName from TRNEntity
    select id, name from TRNTelcomType

    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.