ECO II and ASP.NET Web Applications

By: Bob Swart

Abstract: This tutorial demonstrates the new capabilities of Enterprise Core Objects (ECO) II to be used in ASP.NET Web applications with Borland. Delphi. 2005.

Introduction

The Example Application.

EcoSpaceProvider and Pool Size

PersistenceMapperProvider

#1: PersistenceMapperBdp: InterBase

#2: PersistenceMapperSqlServer and SQL Server / MSDE

#3: PersistenceMapperBdp: IBM DB2 UDB

EcoSpace and PersistenceMapperSharer

Design ECO Model

From Model to Database

The GUI on the Model

Summary

by Bob Swart, Bob Swart Training & Consultancy

    Introduction

Delphi 2005 contains support for using ECO (Enterprise Core Objects) in ASP.NET Web applications. ECO is a persistence engine with code generator using a model-powered framework and provides a run-time OCL (Object Constraint Language) evaluator and a complete run-time UML meta-model. In this tutorial, we will learn how we can use Delphi 2005 Architect in order to build ASP.NET applications that use ECO, designing an Object Model (EcoSpace) which is made persistent inside a database, and presented in ASP.NET Web forms.

    The Example Application.

The ECO ASP.NET example application is built in a number of steps:

- First, we'll create the ECO ASP.NET application and add a PersistenceMapper to store and share the EcoSpaces

- Then, we'll actually design the example UML Model for our EcoSpace

- Thirdly, we'll generate the schema for the model, so the model is actually made persistent.

- Then, we'll design a visual user interface on top of the EcoSpace, using ASP.NET controls

- Finally, we'll deploy and test the application.

The example application uses InterBase, but you are free to use any other BDP-compatible database to store the EcoSpace.

- Start Delphi 2005 Architect

- Do File | New - Other, and from the Delphi for .NET Projects category in the Object Repository, select the ECO ASP.NET Web Application target.

Figure 1. Delphi 2005 Object Repository

- Click on OK to start the New ECO ASP.NET Web Application wizard

Figure 2. New ECO ASP.NET Web Application Wizard

- Specify Eco2WebApp as name for the name project, which will be created in the c:\inetpub\wwwroot\Eco2WebApp directory.

- Click on OK to generate the new project.

It is now recommended to compile, close and reopen the project in order to make sure that the different ECO components and properties will keep their values.

- Do Project | Compile Eco2WebApp (Ctrl+F9) to compile the project.

- Do File | Close to close the project (say Yes to save any changes if you are prompted).

The Eco2WebApp project will now appear on the welcome page in the list of recent projects.

- Click on the Eco2WebApp link in the list of recent projects, or do File | Open Project and open the Eco2WebApp project again.

If you take a look at the Project Manager, you can see the different files that make up the ECO ASP.NET Web Application.

Click to see full-sized image

Figure 3. Project Manager

    EcoSpaceProvider and Pool Size

The ASP.NET Web Forms application should be able to handle multiple requests. And each request needs its own instance of an EcoSpace (the EcoSpaces themselves are in-memory object spaces that cannot be shared among processes). It would take a lot of processing power (and/or memory) to create a new instance of an EcoSpace for each incoming request, so ECO uses a pool with EcoSpaces instead.

The EcoSpaceProvider can be used by every page in the ASP.NET application to get an instance of an EcoSpace from the pool (and to return the EcoSpace to the pool - with or without any changes that were made to it). There are three options for using the EcoSpace pool, that can be configured in the EcoSpaceProvider.pas unit. Line 10-12 of this unit, contains the following default assignment for the value of the EcoSpaceStrategyHandler's SessionStateMode property:

// ToDo: Configure the strategy for the provider by changing the constant
const
   MODE: EcoSpaceStrategyHandler.SessionStateMode =
     EcoSpaceStrategyHandler.SessionStateMode.IfDirty;

The value IfDirty means that the EcoSpace will be kept in the user session if there are any changes made to it (i.e. if it's "dirty"). This will allow an ASP.NET application to reuse the EcoSpace and its contents/state in multiple requests.

Apart from IfDirty, you can also specify Never and Always as values for the SessionStateMode. Never means that the EcoSpace is never cached in the user session, and always returned to the pool (any uncommitted changes will be lost - EcoSpace will revert to original value), while Always means that the EcoSpace is always cached in the user session, until the session expires, at which time the EcoSpace is returned to the pool.

- On line 12 of EcoSpaceProvider.pas, you can change the value of IfDirty to Always in order to ensure that each user will always have the EcoSpace cached in their user session, even if no changes were made to it. Keep in mind, however, that this will consume a lot of resources on the server and possibly interfere with performance. The most resource-friendly solution would be to set SessionStateMode to Never, which discards the pooled EcoSpace after every request.

When it comes to the pool itself, you can configure the maximum number of EcoSpaces that are kept in the pool in the web.config file. At the bottom of this file, you'll find the following appSettings:

<!--  Application settings
      Setting MaxPool to >0 will enable pooling.
      Pooled Ecospaces will be discarded when they reach MaxAge seconds
-->
<appSettings>
  <add key = "Borland.Eco.Web.MaxPool" value = "0" />
  <add key = "Borland.Eco.Web.MaxAge" value = "600" />
</appSettings>

*Note that by default, the MaxPool is assigned to 0, meaning no pooling is done. That means each request will create its own instance of the EcoSpace, unless one is in the user session already.

The reason pooling is off by default is that it only works correctly if you use a PersistenceMapperProvider and a Database PersistenceMapper (i.e it won't work with the PersistenceMapperXML) and if the SyncActive property is set to True on the PersistenceMapper. This will be covered in more detail later in the tutorial.

    PersistenceMapperProvider

When sharing EcoSpaces among multiple requests, the important aspect is being able to correctly synchronize (changes from) multiple EcoSpaces among each other. This is taken care of by the PersistenceMapper. As a consequence, all EcoSpaces that are used in a multi-user environment (like ASP.NET) must be connected to the same PersistenceMapper in order to synchronize correctly.

Sharing PersistenceMappers is done through a so-called PersistenceMapperProvider, which is present in the EcoPersistenceMapperProvider unit which is already created as part of ECO ASP.NET applications. In a single-user application design, we could place PersistenceMapper components on the EcoSpace unit, but in a multi-user / ASP.NET architecture we must place the PersistenceMapper components on the EcoPersistenceMapperProvider unit instead.

- In the project manager, double-click on the EcoPersistenceMapperProvider.pas file, to open the designer for the ECO PersistenceMapperProvider.

There are three different PersistenceMapper components available in the Enterprise Core Objects category of the Tool Palette: PersistenceMapperBdp, PersistenceMapperXml, and PersistenceMapperSqlServer.

The PersistenceMapperXml component works with XML files, but cannot be synchronized between multiple requests or users, so we should not use this PersistenceMapper, unless you want to build an ASP.NET Web application that uses a read-only EcoSpace.

There is a special PersistenceMapperSqlServer that you can use in combination with Microsoft SQL Server. However, the PersistenceMapperBdp control allows you to use any Borland Data Provider for .NET, including Microsoft SQL Server / MSDE, but also InterBase, IBM DB2, Informix and MS Access.

    #1: PersistenceMapperBdp: InterBase

We will now use a PersistenceMapperBdp to connect to InterBase as DBMS to store the EcoSpace. The next subsection will use a PersistenceMapperSqlServer in order to use a SQL Server / MSDE database to store the EcoSpace, and a third subsection will use a PersistenceMapperBdp again, this time connecting to an IBM DB2 UDB database.

- Place the PersistenceMapperBdp component on the designer area of the EcoPersistenceMapperProvider unit.

- Hold your mouse cursor over the PersistenceMapperBdp component, and wait for the tooltip to appear and tell you which steps to perform next.

Figure 4. PersistenceMapperBdp tooltip hints

However, before we can specify the connection property, we should first make sure that there is a database (and BdpConnection component) that we can connect to.

First, you need to configure the SqlDatabaseConfig property of the PersistenceMapperBdp, which by default contains an <<EMPTY PERSISTENCE MAPPER CONFIG>> value. You can specify a correct value by using one of the verbs at the bottom of the Object Inspector.

- Select the PersistenceMapperBdp component, and assuming we want to use InterBase as persistence database, click on the InterBase dialect 3 setup link.

Clicking on this verb doesn't seem to do much (no dialog is started), but if you look again, you'll notice that the SqlDatabaseConfig property is now assigned a value specifically for the InterBase setup.

The next step involves a BdpConnection component that maps to the specific InterBase database that we want to use to store our EcoSpace object model in. It is highly recommended to use an empty InterBase database to start with.

- In order to create a new empty InterBase table, go to the C:\Program Files\Borland\InterBase\Bin directory and start isql.exe - the command-line SQL interface to InterBase (make sure InterBase itself is running, too).

- Enter the following command:

CREATE DATABASE 'C:\Data\EcoASP.gdb' PAGE_SIZE 2048;
EXIT;

This will create a new, empty EcoASP.gdb database in the C:\Data directory (obviously, feel free to place this database anywhere else).

Once the new empty InterBase database EcoASP.gdb is created, we need to add a BDP connection to it.

- From the Data Explorer, right-click on the InterBase node and select the "Add Connection" menu option to create a new BDP connection. Make sure to specify InterBase as provider, and call it EcoASP:

Figure 5. Add New Connection

- Click on OK to create the new InterBase connection EcoASP.

- Right-click on the new connection and select the "Modify Connection" option to get the Connection Editor dialog.

- In this dialog, you need to change the value for the Database property to localhost:C:\Data\EcoASP.gdb (which is the machinename followed by the actual location of the EcoASP.gdb database file).

- Click on the Test button to make sure that you can make a connection to the EcoASP.gdb database on localhost.

Figure 6. Connecting to InterBase EcoASP.gdb

- Click on OK to close the Connections Editor.

- Drag the EcoASP connection from the Data Explorer and drop it onto the EcoPersistenceMapperProvider designer.

This will result in a BdpConnection component that is configured to use the InterBase EcoASP database.

- Select the PersistenceMapperBdp component and point its Connection property to the BdpConnection component.

We must now tell the EcoPersistenceMapperProvider to use this PersistenceMapper.

- Click on the EcoPersistenceMapperProvider designer, and in the Object Inspector select the PersistenceMapperBdp as the value for the PersistenceMapper property.

- Also set the SyncActive property of the PersistenceMapperBdp to true.

    #2: PersistenceMapperSqlServer and SQL Server / MSDE

If you do not want to use InterBase, or just want to use SQL Server / MSDE to store the EcoSpace, then you can use a PersistenceMapperSqlServer component.

- Place a PersistenceMapperSqlServer component on the EcoPersistenceMapperProvider designer.

- From the Data Components category of the Tool Palette, place a SqlConnection component on the EcoPersistenceMapperProvider designer.

- We must now also create an empty SQL Server / MSDE database. This can be done using the following command:

osql -E localhost -i ecoasp.sql

where . is the name of the machine, and ecoasp.sql contains the following lines:

CREATE DATABASE EcoASP
GO

The result of running osql on this .sql file should be a new database called EcoASP.

- Select the SqlConnection component, and click on the ConnectionString property.

- In the Data Link Properties dialog, enter the name of the server (which can be . to use the local machine), use Windows NT integrated security, and select the database on the server (the drop-down combobox should contain EcoASP in its list):

- Click on Test Connection to ensure that we can connect to the EcoASP database.

Figure 7. Connecting to SQL Server / MSDE EcoASP database

- Click on OK to close the ConnectionString Editor.

- Select the PersistenceMapperSqlServer component and point its Connection property to the SqlConnection component.

- At the bottom of the Object Inspector, click on the right link to setup SQL Server (in this case, the SQL Server setup link).

We can now tell the EcoPersistenceMapperProvider to use the PersistenceMapperSqlServer instead of the PersistenceMapperBdp.

- Click on the EcoPersistenceMapperProvider designer, and in the Object Inspector select the PersistenceMapperSqlServer as the value for the PersistenceMapper property.

- Also set the SyncActive property of the PersistenceMapperSqlServer to true.

    #3: PersistenceMapperBdp: IBM DB2 UDB

As third alternative, we can use another PersistenceMapperBdp, this time connecting to an IBM DB2 UDB database.

For this to work, you need to have installed the IBM DB2 UDB Developer Edition that comes on a separate CD-ROM with Delphi 2005.

- From the IBM DB2 General Administrator Tools start the Control Center, and open up the treeview for your system, DB2 instances and databases.

- Right-click on the Databases node, and select "Create - Database using Wizard".

This will result in a 7-step dialog where you only need to specify the name of the database (EcoASP), and leave all other options at their default value. The actual SQL command, which can also be passed on the DB2 command-line processor is:

CREATE DATABASE ECOASP ON C: USING CODESET IBM-1252 TERRITORY US COLLATE USING SYSTEM;

After you've created the new database, you may want to run the Configuration Advisor to tune your database (this is not needed at this time).

- Place a new PersistenceMapperBdp component on the designer area of the EcoPersistenceMapperProvider unit.

- Select the PersistenceMapperBdp component, and assuming we want to use IBM DB2 UDB as persistence database, click on the DB2 setup link (note that this option might be hidden under the next pane in the Object Inspector, so you may have to resize the Object Inspector in order to be able to click on it).

- From the Data Explorer, right-click on the DB2 node and select the "Add Connection" menu option to create a new BDP connection. Make sure to specify DB2 as provider, and call it DB2EcoASP (you cannot call it EcoASP, since there already is a connection called EcoASP).

- Right-click on the new DB2EcoASP connection and select the "Modify Connection" option to get the Connection Editor dialog.

- In this dialog, you need to change the value for the Database property to EcoASP, and you may also need to specify the username and password.

- Click on the Test button to make sure that you can make a connection to the IBM DB2 UDB EcoASP database.

- Click on OK to close the Connections Editor.

- Drag the DB2EcoASP connection from the Data Explorer and drop it onto the EcoPersistenceMapperProvider designer.

This will result in a second BdpConnection component that is configured to use the IBM DB2 UDB EcoASP database.

- Select the second PersistenceMapperBdp component and point its Connection property to the new BdpConnection component.

We can now tell the EcoPersistenceMapperProvider to use the new PersistenceMapperBdp instead of the PersistenceMapperSqlServer or the first PersistenceMapperBdp.

- Click on the EcoPersistenceMapperProvider designer, and in the Object Inspector select the new PersistenceMapperBdp as the value for the PersistenceMapper property.

- Also set the SyncActive property of the PersistenceMapperBdp to true.

    EcoSpace and PersistenceMapperSharer

The PersistenceMapperProvider will hold a singleton PersistenceMapper at runtime, that can be used by multiple EcoSpaces. To verify the connection of the EcoSpaces to the PersistenceMapperProvider, you can open the EcoSpace unit.

- In the Project Manager, double-click on the Eco2WebAppEcoSpace.pas unit.

As you will notice, the Eco2WebAppEcoSpace unit contains a PersistenceMapperSharer component. The MapperProviderType property of the PersistenceMapperSharer is assigned to our EcoPersistenceMapperProvider.TEcoPersistenceMapperProvider. If the value is not assigned correctly, please recompile the application and open the dropdown combobox and select the (only) value for the MapperProviderType property.

This will ensure that all EcoSpaces will use the PersistenceMapper you set up to store the EcoSpace in your choice of data store.

    Design ECO Model

Time to design the model.

- Go to the Model View and open up the CoreClasses node.

Figure 8. Model View and CoreClasses

The CoreClasses package node (with the grey folder icon) contains a CoreClasses diagram node.

- Double-click on the CoreClasses diagram node to start the UML Designer.

This is where you can design your objects using the UML techniques. By right-clicking on the UML Designer, you can add new classes, and inside classes you can add attributes, operations or constructors. Furthermore, you can use the drawing components from the special UML Class Diagram category of the Tools Palette (shown in Figure 9).

Figure 9. ECO Class Diagram drawing tools

- Right-click on the UML Designer and create a new class, call it Person.

- Right-click on Person and add three attributes: FirstName, LastName and Sex, all of type string.

*Note that you can press insert to add more attributes, and can use the Object Inspector to set the Name, Type and Visibility properties of the new attributes.

- Right-click again on the class Person and add an operation called FullName: string.

Note that the UML Designer will automatically add a () to FullName, but make sure you specify the result type (the Returns property in the Object Inspector), otherwise you're defining a procedure FullName instead.

- To implement the FullName operation, right-click on the operation and select "Go to Definition".

This will bring you to the CoreClassesUnit inside the class definition of the Person class, just on top of the line for the FullName method:

    [UmlElement]
    function FullName(): string;

- Press Ctrl+Shift+Down in order to find the implementation of this method (which is still empty at this time).

- Implement the FullName method as follows, using the fact that the values of the FirstName and LastName fields are stored in private fields with an _ prefix

procedure Person.FullName();
begin
  Result := _FirstName + ' ' + _LastName;
end;

A person can have an e-mail address, or more than one actually. But since we do not know how many e-mail address a person can have, or how many people can be reached by the (shared) e-mail address, we cannot just add the address information to the person. So, let's design a new class to hold e-mail address information.

- Go back to the UML Diagram, right-click on the UML Designer and add a new class called Address.

- Right-click on Address and add 2 new attributes to it of type string, called Email and Website.

Now, in order to model the relation between a Person and an Address, we need to add an association object between them.

- Click on the Association object in the Tools Palette, and then click on Address and Person to connect them using a new association.

- Use the Object Inspector to set the name to something meaningful, like NetAddress.

By default, the associations created have a 0..1 multiplicity at both ends. This means that the default association is expected to mean that a Person can have 0 or 1 Addresses, and an Address can have (be used by) 0 or 1 Persons. Technically, that may be right - a person can be without e-mail address, and an e-mail address might be invalid, unused or blocked. However, we probably don't want to store invalid e-mail address, and an e-mail address can also be used by more than one person.

- Change the multiplicity of the association to be 0..* at the Address end (a Person can have zero or more Address), and 1..* at the Person end (an Address can have 1 or more Persons).

Figure 10. Person-Address Design

The Person class is still very generic. In fact, it may be too generic, so let's add some derived classes.

- Right-click on the UML Designer again and add a new class called Friend.

- Click on the Generalization/Implementation designer item in the ECO category of the Tool Palette, and then drag from Friend to Person, in order to specify that Friend is derived from Person.

- Right-click on the Friend class, and add an attribute called BirthDate of type DateTime.

Apart from the BirthDate attribute, we also may want to add an operation called Age to calculate the Age of the Friend, returning an integer.

- Right-click on the Friend class, and add an operation "Age: Integer".

- Right-click on the Age operation, and select "Go to Definition"

- Implement the Friend.Age() method as follows:

function Friend.Age(): integer;
var
  Year,Month: Integer;
begin
  Year := DateTime.Now.Year - Self._BirthDate.Year;
  Month := DateTime.Now.Month - Self._BirthDate.Month;
  if Month = 0 then // birthday month...
    if (DateTime.Now.Day - Self._BirthDate.Day) < 0 then
      Month := -1;
  if Month < 0 then Dec(Year); // Birthday not yet this year
  Result := Year
end;

- Compile the project to make sure there are no syntax errors and to make sure the model itself is compiled.

As the final step, we can express the fact that we're only interested in Friends (and not "regular" people), so we should only create instances of Friends. This can be enforced by setting the Abstract property of the Person class to True.

All this designing leads to the UML Diagram that can be seen in the following screenshot:

Figure 11. ECO Person-Friend and Address UML Design

    From Model to Database

We're almost done with making the model persistent. What's missing is the actual link between our EcoSpace object model and the database schema.

- Open the EcoPersistenceMapperProvider again

- Right-click on the designer, and select "Generate Schema"

Figure 12. Generate Schema

If you see less than 9 tables, then you may have to click on Cancel to close the dialog and recompile the project (in order to make sure the model is fully compiled).

- Click on OK to create the ECO tables in the database.

*Note: If you've used DB2 to store the ECO tables, and are using Delphi 2005 without the first update, then you need to perform a few more steps before you can continue.

- After you have created the database, locate the table ECO_ID, which is most likely empty.

- Insert a new row in this table using the following statement:

     INSERT INTO ECO_ID (BOLD_ID) VALUES (1)

Note that the column is called BOLD_ID, the table is called ECO_ID.

Once this is done, we can start to use the objects in the EcoSpace, by building ASP.NET Web Forms on top of them.

    The GUI on the Model

In order to build the GUI, we need to access the ASP.NET Web forms.

- In the Project Manager, double-click on the WebForm1.aspx file to open the HTML designer.

You may notice a rhRoot component in the non-visual component area of the HTML designer. This is the ReferenceHandle between the Web Form and the EcoSpace (and all objects inside it).

We need to add an additional component from the Enterprise Core Objects category, namely an ExpressionHandle. An ExpressionHandle is linked to either a ReferenceHandle or another ExpressionHandle, and can be used to evaluate an OCL (Object Constraint Language) expression.

- Place an ExpressionHandle component on the Web Form.

- Point the RootHandle property of the ExpressionHandle to the rhRoot component.

Using the ExpressionHandle, we can build OCL expressions that can be displayed, for example the collection of all Friends inside a DataGrid.

- Select the ExpressionHandle component and double-click on the Expression property, which will give you the OCL Expression Editor, showing the class types inside the EcoSpace (Address, Friend, Person) as well as the ECOModelRoot node.

- Double-click on the Friend class, which shows you the properties and method for it, such as allInstances:

Figure 13. OCL Expression Editor for Friend.allInstances

- Complete the expression Friend.allInstances, and click on OK to close the dialog.

- Set the AddExternalId property of the ExpressionHandle to True.

- Place a DataGrid component from the Web Components category of the Tool Palette on the ASP.NET Web Form.

- Assign the DataSource property of the DataGrid to the ExpressionHandle component.

- Set the DataKeyField property of the DataGrid to ExternalId.

This will show the meta data in the DataGrid, including the ExternalId field. This field is the key field for the objects, and while it should be used, you may not want to display it in the DataGrid.

Figure 14. DataGrid with Friend.allInstances at Design-Time

- Click on the Auto Format link at the bottom of the Object Inspector, and select one of the display formats for the DataGrid, for example Professional 1.

- Click on the Property Builder link at the bottom of the Object Inspector to bring up the DataGrid properties dialog.

- Go to the Columns page, and uncheck the option to "Create columns automatically at runtime".

- Select the Firstname, Lastname, Sex, and Birthdate fields to be displayed, as follows:

Click to see full-sized image

Figure 15. DataGrid Properties dialog

- Click on OK to close the DataGrid properties dialog.

The DataGrid on the ASP.NET Web Form will now only show four columns for the Firstname, Lastname, Sex, and Birthdate fields.

This will result in a working ASP.NET Web page connecting to the EcoSpace, made persistent in the EcoASP.gdb database. The only thing we haven't considered yet is the fact that the database is still empty at this time.

- Place a Button from the Web Components on the ASP.NET Web Forms right below the DataGrid.

- Set the Text property of the Buttom component to "New Friend".

- Double-click on the Button, and write the following event handler to add a new Friend to the EcoSpace:

procedure TWebForm1.Button1_Click(sender: System.Object; e: System.EventArgs);
var
  NewFriend: Friend;
begin
  NewFriend := Friend.Create(EcoSpace);
  NewFriend.Firstname := 'Bob';
  NewFriend.Lastname := 'Swart';
  NewFriend.Sex := 'Male';
  NewFriend.Birthdate := Convert.ToDateTime('1964/11/07');
  UpdateDatabase;
  DataBind;
end;

This will create a new friend, with my name, and will also save the database and display it in the DataGrid, but it won't allow you to edit the new friend and change its properties. For that, we need to modify the DataGrid a bit more.

- Select the DataGrid, and click on the Property Builder link at the bottom of the Object Inspector again.

- Go to the Column page again, and in the Available columns listbox, scroll down until you get to the Button Column.

- Select the "Edit, Update, Cancel" as well as the Delete button, and make sure they appear in the Selected columns listbox:

Click to see full-sized image

Figure 16. DataGrid Properties dialog (again)

You can further customize the Edit, Update, Cancel and Delete buttons if you wish. By default, they are shown as LinkButton, but you can change that to PushButtons, or you can change their Text, etc. (this is left as optional exercise for the reader).

- Close the DataGrid Properties dialog, select the DataGrid again, and in the Object Inspector click on the Events tab.

- Open up the drop-down combobox for the CancelCommand event, and assign it to DataGrid_CancelCommand.

- Do the same with the DeleteCommand (to DataGrid_DeleteCommand), EditCommand (to DataGrid_EditCommand), and UpdateCommand (to DataGrid_UpdateCommand).

- Compile and run the application, which starts with an ASP.NET Web Form and an empty DataGrid.

Figure 17. ECO 2 ASP.NET at run-time

- Click on the New button to add a new empty Friend object to the EcoSpace, which is automatically displayed in the DataGrid.

Figure 18. ECO 2 Object in ASP.NET web page

You can now edit the attributes. After you click on the Edit button, two other buttons appear: Cancel and Update. After you click on the Update button, the changes are saved to the EcoSpace again.

We should now try to add Addresses, resulting in a master-detail relationship with another DataGrid on a new page.

- Close the browser, and return to the WebForm1.aspx file of the Eco2AspWeb project in the Delphi 2005 IDE.

- Select the DataGrid, and click on the Property Builder verb at the bottom of the Object Inspector.

- In the Columns page, add a new column of type HyperLink.

- For the new HyperLink column, set the Text property to Details, the URL field drop-down combobox property to ExternalID, and the URL format string property to FriendEmail.aspx?RootId={0}

Click to see full-sized image

Figure 19. New HyperLink Field for Details

- Click on OK to create the new HyperLink button in the DataGrid.

All this means that each Friend object in the DataGrid will get a hyperlink with the text Details, that will link to the page FriendEmail.aspx (that we still need to make), passing the ExternalID of the current object on the URL.

We now need to create the new ECO Web Form, called FriendEmail.aspx, and make sure it will show the current Friend as well as all related Address objects.

- Do File | New - Other, and from the New ASP.NET Files subcategory in the Delphi for .NET Projects category, select the ECO ASP.NET Page icon.

Figure 20. New ECO ASP.NET Page

- Click on OK to create the new ECO ASP.NET Web Form.

- Do File | Save As and save the new Web Form in file FriendEmail.aspx (the one that we already mentioned in the HyperLink field of the first page).

If you take a look at the source code of the ECO ASP.NET Web Forms, you'll notice that in the Page_Load event, the form looks for the RootId parameter passed on the URL, and initializes the rhRoot component with this particular element:

procedure TWebForm2.Page_Load(sender: System.Object; e: System.EventArgs);
var
  Id: string;
begin
  EcoSpace.Active := True;
  Id := Request.Params['RootId'];
  if Assigned(Id) and (Id <> '') then
    rhRoot.SetElement(ObjectForId(Id));
  if not IsPostBack then
    DataBind;
  // TODO: Put user code to initialize the page here
end;

This means that the rhRoot points to the right Person when we enter the detail page.

Before we can continue, we need to make sure that the second Web Form can access the objects and types from the CoreClassesUnit.

- Go to the top of the FriendEmail.pas unit, and add the CoreClassesUnit to the uses clause of the interface section.

- Click on the rhRoot component in the HTML Designer, and set the EcoSpaceType property to Eco2WebAppEcoSpace.TEco2WebAppEcoSpace.

- Set the StaticValueType to Friend, to indicate that the element that the rhRoot points to is a Friend (so we get correct design-time support).

- Place a new ExpressionHandle on the Web Form, set the RootHandle property to rhRoot, and the AddExternalId property to True.

- Double-click on the Expression property, and set the Expression to self (pointing to the current Friend).

- Place a new ExpressionHandle on the Web Form, set the RootHandle property to rhRoot, and the AddExternalId property to True.

- Double-click on the Expression property, and set the Expression to self.Address (pointing to the addresses associated with the current Friend).

This will make sure that the second ExpressionHandle lists all the Address objects that belong to the Friend object. We can display them in another DataGrid on the Web Form.

- Place a DataGrid on the Web Form, and set its DataSource property to the first ExpressionHandle (this will show the current Friend object), and the DataKeyField property to ExternalId.

- Place a second DataGrid just below the first one on the Web Form, and set its DataSource property to the second ExpressionHandle (this will show all the associated Address objects), and the DataKeyField property to ExternalId.

- Use the Auto Format verb at the bottom of the Object Inspector to give the two DataGrids a nice look, like Professional 1.

At this time we can display the current Friend and the list of associated Addresses, but we cannot add a new Address, or edit the Friend or Address information, yet.

- Select the first DataGrid (the one showing the Friend object) and click on the Property Builder verb at the bottom of the Object Inspector to start the Property Builder.

- On the Columns page, uncheck the "Create columns automatically at runtime" option, and instead place all individual fields (Firstname, Lastname, Sex and BirthDate) to the list of selected columns.

- From the Button Column type, add a Edit, Update, Cancel button (we do not want to add a Delete button, since this is only the place to edit Friends, not delete them).

- Click on OK to close the Property Builder dialog and add the columns to the DataGrid.

- Select the first DataGrid, and in the Events tab of the Object Inspector, hook the CancelCommand to DataGrid_CancelCommand, the EditCommand to DataGrid_EditCommand, and the UpdateCommand to DataGrid_UpdateCommand.

- Select the second DataGrid (the one showing the associated Address objects) and click on the Property Builder verb at the bottom of the Object Inspector.

- On the Columns page of the Property Builder dialog, uncheck the "Create columns automatically at runtime" option, and instead place all individual fields (Email and Website) to the list of selected columns.

- From the Button Column type, add an Edit, Update, Cancel as well as a Delete button.

- Click on OK to close the Property Builder dialog and add the columns to the DataGrid.

- Select the first DataGrid, and in the Events tab of the Object Inspector, hook the CancelCommand to DataGrid_CancelCommand, the DeleteCommand to DataGrid_DeleteCommand, the EditCommand to DataGrid_EditCommand, and the UpdateCommand to DataGrid_UpdateCommand.

- Place a normal Button component from the Web Controls category of the Tool Palette, and place it next to the second DataGrid.

- Set the Test property of the Button to "New Address".

- Double click on the Button, and write the following code in the event handler:

procedure TWebForm2.Button1_Click(sender: System.Object; e: System.EventArgs);
var
  NewAddress: Address;
begin
  NewAddress := Address.Create(EcoSpace);
  NewAddress.Email := 'email';
  NewAddress.Website := 'www';
  NewAddress.Person.Add(rhRoot.Element.AsObject as Friend);
  UpdateDatabase;
  DataBind;
end;

This will add a new Address to the EcoSpace, and add the current Friend to the list of persons that belong to this Address.

- Save All, Compile and Run the application. You can now add new Friends as well as new Addresses to the selected Friend.

Figure 21. Edit new Address, associated with Friend

There is no button to get back to the first page from the detail page, but I leave that as exercise for the reader.

    Summary

This completes the tutorial on Enterprise Core Objects II with ASP.NET; the model-powered framework and Object Model Persistence functionality in the Architect edition of Delphi 2005 brought to the Web.

In this tutorial, you have learned how to build an ECO ASP.NET Web Forms application, how to specify the PersistenceMappers in order to make the EcoSpace persistent, how to design the UML model itself, and how to build visual Web Forms using ASP.NET controls to display and work with the data.

For more information on ECO, visit the ECO Info Center.



Server Response from: ETNASC04