Flex Data Services for .NET with WebORB
Part 2 - Server-side, fetching data
Search:
home / articles / flex integration  

OVERVIEW
This is part 2 of the series, part 1 is available here. This part begins a review of the backend implementation of the Contact Manager example. To compile and run the server-side code you need to have the following software installed:

Part 1 consists of the following sections:

Part 3 reviews the code for handling data updates. It is available here.

If you have any comments about the article, or have any questions about the product and the integration of Flex Data Management Services in WebORB, post them to the our interest group at: http://groups.yahoo.com/group/flashorb/

CLASS DESIGN
The architecture diagram from Part1 depicts the Data Destination box as the server-side component responsible for executing individual data management operations. The diagram below shows a drilldown view into the design of the example's data destination:

The design includes three classes: ContactAssembler, ContactDAO and Contact. The assembler class is the main interface between WebORB and the data. It contains several methods responsible for retrieving or modifying data in the data store. ContactAssembler delegates all data management operations to ContactDAO, which interfaces directly with the database using .NET's OleDb API. The Contact class represents a record in the database. As you will see shortly the class is optional, since WebORB provides a way to manage data without specific generalization of a database record.
 

DATABASE DESIGN

The database consists of a single table - contact. Each row in the table represents a record of contact information with person's name, address and phone number:

CODE REVIEW - READING DATA

Below are the methods from the Examples.Flex.contact.ContactDAO class responsible for fetching data from the database:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
51
52
53
54
55
56
57

namespace Examples.Flex.contact
{
  public
class
ContactDAO
 
{
    private
static string
cnxString = "very long cnx string goes here";

    public
IList getContacts()
    {

      return
loadContactsAsArray( "SELECT * FROM contact ORDER BY lastName"
);
    }


    public IList getContacts( string name )
    {

      return loadContactsAsArray( "SELECT * FROM contact WHERE firstName LIKE '%"+
                                  name +
"%' OR lastName LIKE '%" + name +
                                  "%' ORDER BY lastName"
);
    }


    private ArrayList loadContactsAsArray( string query )
    {
      ArrayList list = new ArrayList();
      OleDbConnection connection = null;
      OleDbCommand command = null;
      OleDbDataReader reader = null;

      try
      {
        connection = new OleDbConnection( cnxString );
       
command = new OleDbCommand( query, connection );
        connection.Open();
        reader = command.ExecuteReader();

        while( reader.Read() )
        {
          Contact contact = new Contact();
          contact.contactId = reader.GetInt32( reader.GetOrdinal(
"contactId" ) );
          contact.firstName = GetString( reader,
"firstName" );
          contact.lastName = GetString( reader,
"lastName" );
          contact.address = GetString( reader,
"address" );
          contact.city = GetString( reader,
"city" );
          contact.zip = GetString( reader,
"zip" );
          contact.state = GetString( reader,
"state" );
          contact.phone = GetString( reader,
"phone" );

          list.Add( contact );
        }
      }
      finally
      {
        if( reader != null )

          reader.Close();

        connection.Close();
      }
      return list;

    }
....

The getContacts() method without arguments (lines 7-9) fetches all records from the database. The other getContacts method (lines 12-17) loads all the contacts where either first name or last name contain the given string. Both methods reuse the same logic by providing different SQL queries (lines 9 and 14). The method with the logic for executing a SELECT query (lines 19-56) creates a connection, command and runs the query (lines 28-31). The code processes all records fetched from the database in a loop and creates a Contact object for each record (lines 35-43). The method returns a collection of all contact objects as an ArrayList.

The ContactAssembler class delegates to the ContactDAO.getContacts methods to load the data (lines 8 and 14 in the code below).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

namespace Examples.Flex.contact
{
 
public class ContactAssembler
  {

    public
object loadContacts()
    {
      ContactDAO dao = new ContactDAO();
      return dao.getContacts();
    }

    public
object loadContacts( string name )
    {
     
ContactDAO dao = new ContactDAO();
     
return
dao.getContacts( name );
    }
......

WebORB invokes the loadContacts methods from the ContactAssembler class when a Flex client requests data from the data store or runs a search query. A mechanism to register ContactAssembler with WebORB is described later in this article.
 

CODE REVIEW - READING DATA -A DATASET APPROACH

There is an alternative approach for data fetching implemented in the ContactDAO class. The approach avoids creation of Contact objects for each data row and simplifies the implementation:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

namespace Examples.Flex.contact
{
  public
class
ContactDAO
 
{
    private
static string
cnxString = "very long cnx string goes here";
 
    public
DataSet getContacts()
    {

      return
loadContactsAsDataSet( "SELECT * FROM contact ORDER BY lastName"
);
    }


    public
DataSet getContacts( string
name )
    {

      return
loadContactsAsArray( "SELECT * FROM contact WHERE firstName LIKE '%"+
                                  name +
"%' OR lastName LIKE '%" + name +
                                  "%' ORDER BY lastName"
);
    }

 
  private DataSet loadContactsAsDataSet( string query )
    {

      DataSet
dataset = new DataSet
();
      OleDbDataAdapter
dataAdapter = new OleDbDataAdapter
( query, cnxString );
      dataAdapter.Fill( dataset );

      return
dataset;
    }
.....

The primary differences between this and the previous approaches are:

  1. The return type of the getContacts() methods (lines 7 and 12)  - the return type is System.Data.DataSet

  2. The implementation of the method that executes a database query (lines 19-25) - the new approach creates an untyped DataSet

Below is a modified version of ContactAssembler supporting the DataSet approach:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

using Weborb.Data;

namespace
Examples.Flex.contact
{
 
public class ContactAssembler
  {
    [
ReturnType( "samples.contact.Contact" ) ]
    public
object loadContacts()
    {
      ContactDAO dao = new ContactDAO();
      return dao.getContacts();
    }

   
[ReturnType( "samples.contact.Contact" ) ]
    public
object loadContacts( string name )
    {
     
ContactDAO dao = new ContactDAO();
     
return
dao.getContacts( name );
    }
......

Notice the method attributes on lines 7 and 14. Since the getContacts methods return an untyped DataSet, WebORB needs additional information on the data type contained in the return value  from the client perspective. When WebORB sends data query result to the client application, it needs to serialize each record as a samples.contact.Contact client-side type. In the first approach, that information came from a configuration file (Examples.Flex.contact.Contact is mapped to samples.contact.Contact), but in the DataSet approach, the Contact class is not used, so method attribute comes to the rescue.
 

CONFIGURATION

ContactAssembler is the example's only class WebORB interfaces with to handle all data management operations. The class must be registered in flex-data-service.xml located in the WEB-INF\flex folder:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

<destination id="contact">
  <
adapter ref="dotnet-dao" />

  <
properties>
    <
source>Examples.Flex.contact.ContactAssembler</source>
    <
scope>application</scope>

    <
metadata>
      <
identity property="contactId"/>
    </
metadata>

    <
network>
      <
session-timeout>20</session-timeout>
      <
paging enabled="false" pageSize="10" />
    </
network>

    <
server>
      <
fill-method>
        <
name>loadContacts</name>
      </
fill-method>

      <
fill-method>
        <
name>loadContacts</name>
        <
params>System.String</params>
      </
fill-method>
    </
server>

  </
properties>
</
destination>

Notice full name of the class on line 5. The <scope> element on line 6 specifies that only one instance of the ContactAssembler class should be created. A registration for both loadContacts methods of the class appears on lines 18-25.

 
Copyright © 2003-2006 Midnight Coders, LLC.  Privacy Policy | Contact Webmaster
Home | Products | Customers | Download | Licensing | Forum | Developers | About