Finding Domain Objects

I’d like to discuss finding domain objects using Neo against the Northwind catalog. The code has been tested against Neo 1.2.1 and the following schema:

 

<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?>

<!DOCTYPE database SYSTEM "file:norque.dtd">

<?neo path="../../../Tools/CodeGen/Resources"?>

<database name="northwind" package="Northwind.Model" defaultIdMethod="none">

  <table name="Customers" javaName="Customer">

    <column name="CustomerId"    javaName="Id" primaryKey="true" required="true" type="CHAR" size="5" />   

    <column name="CompanyName"   javaName="CompanyName"          required="true" type="VARCHAR"    size="40" />   

    <column name="ContactName"   javaName="ContactName"                          type="VARCHAR"    size="30" />   

    <column name="ContactTitle"  javaName="ContactTitle"                         type="VARCHAR"    size="30" />     

    <column name="Address"       javaName="Address"                              type="VARCHAR"    size="60" />

    <column name="City"          javaName="City"                                 type="VARCHAR"    size="15" />

    <column name="Region"        javaName="RegionCode"                           type="VARCHAR"    size="15" />

    <column name="PostalCode"    javaName="PostalCode"                           type="VARCHAR"    size="10" />

    <column name="Country"       javaName="Country"                              type="VARCHAR"    size="15" />

    <column name="Phone"         javaName="PhoneNumber"                          type="VARCHAR"    size="24" />

    <column name="Fax"           javaName="FaxNumber"                            type="VARCHAR"    size="24" />

  </table> 

</database>

 

Neo separates finder behavior in it’s entity factories which can be packaged within the domain layer (the layer where you’re model classes reside). You then have three different interfaces to find your domain objects, Templates, Qualifiers, and FetchSpecifications.

 

Templates

 

Templates are particularly useful because they have all the properties as the corresponding entity object, including to-one relationships.

 

[Test]

public void SalesRepresentativeWithTemplate()

{

      CustomerList result;

      CustomerTemplate t;

 

      t = new CustomerFactory(context).GetQueryTemplate();

      t.ContactTitle = "Sales Representative";

 

      result = new CustomerFactory(context).Find(t);

      Assertion.AssertEquals("Found wrong number of sales representative", 17, result.Count);

}

 

If you study the Neo documentation closely you’ll notice the methode FindMatchingObjects being refactored to a simple Find overload. Templates work out really well if being used close to the domain specific code.

 

Qualifiers

 

Qualifiers define search criteria’s.

 

[Test]

public void SalesRepresentativeWithPropertyQualifier()

{

      PropertyQualifier q;

      IList result;

 

      q = new PropertyQualifier("ContactTitle", new EqualsPredicate("Sales Representative"));

      result = new CustomerFactory(context).Find(q);

      Assertion.AssertEquals("Found wrong number of sales representative", 17, result.Count);

}

 

As you might have noticed the find method returns an untyped collection. There’s also an overloaded Find which accepts a qualifier format string and in fact does return a CustomerList collection. Another neat feature of qualifiers is that it can use inlined values and multiple clauses. Qualifiers make perfect sense for relative simple search scenario’s.

 

FetchSpecifications

 

Then there is the FetchSpecification. Using a FetchSpecification for searching domain objects enables you to page and sort results. This is done by passing a value indicating the fetch limit, and sort ordering in the constructor.

 

[Test]

public void SalesRepresentativesWithFetchSpecification()

{

      PropertyQualifier q;

      FetchSpecification fSpec;

      CustomerList result;

 

      q = new PropertyQualifier("ContactTitle", new EqualsPredicate("Sales Representative"));

      fSpec = new FetchSpecification(context.EntityMapFactory.GetMap(typeof (Customer)), q);

      result = new CustomerFactory(context).Find(fSpec);

      Assertion.AssertEquals("Found wrong number of sales representative", 17, result.Count);

}

 

[Test]

public void SalesRepresentativesWithLimit()

{

      PropertyQualifier q;

      FetchSpecification fSpec;

      CustomerList result;

 

      q = new PropertyQualifier("ContactTitle", new EqualsPredicate("Sales Representative"));

      fSpec = new FetchSpecification(context.EntityMapFactory.GetMap(typeof (Customer)), q, 10);

      result = new CustomerFactory(context).Find(fSpec);

      Assertion.AssertEquals("Should only fetch up to limit.", 10, result.Count);

}

 

Overview finders interface implemented in CustomerFactory class:

 

public Northwind.Model.CustomerList Find ( Northwind.Model.CustomerTemplate template )

    Member of Northwind.Model.CustomerFactory

 

public Northwind.Model.CustomerList Find ( Neo.Core.FetchSpecification fetchSpecification )

    Member of Northwind.Model.CustomerFactory

 

public new Northwind.Model.CustomerList Find ( System.String qualifierFormat , object[] parameters )

    Member of Northwind.Model.CustomerFactory

 

public new Northwind.Model.CustomerList FindAllObjects (  )

    Member of Northwind.Model.CustomerFactory

 

public new Northwind.Model.Customer FindFirst ( System.String qualifierFormat , object[] parameters )

    Member of Northwind.Model.CustomerFactory

 

public Northwind.Model.Customer FindObject ( System.String pkvalue )

    Member of Northwind.Model.CustomerFactory

 

public new Northwind.Model.Customer FindUnique ( System.String qualifierFormat , object[] parameters )

    Member of Northwind.Model.CustomerFactory

 

public new Northwind.Model.CustomerList FindWithLimit ( System.Int32 limit , System.String qualifierFormat , object[] parameters )

    Member of Northwind.Model.CustomerFactory

 

Factoring the finder logic into entity factory classes where the Neo.Framework.ObjectFactory class acts as the super type seems like a natural fit. One of the things I really like about Neo is it’s versatility for finding domain objects. Though finder logic can complicate a frameworks API, Neo seems to do a great job of packaging a lot of functionality but at the same time maintaining a simple and intuitive API.

 

The Neo distribution comes with a best practices document (neo-x.x.x\neo\docs) which explains when to use what a bit further.

2 Comments

  • Paul, nice explanation. Neo looks very good.

    A couple of simple questions, because I haven't looked at Neo just yet:

    - where does the context come from?

    - does it support spans and aggregated / contained objects?

    - what's the purpose of the javaName in the schema?

  • Thnx,



    &gt; where does the context come from?

    Please refer to my latest post.



    &gt; does it support spans and aggregated / contained objects?



    You'd have to program a little in the auto generated entity classes (which will not be overwritten aka LLBLGen Pro). Note Neo isn't a fully fledged ORM, but an Object Facade over ADO.NET. This means you'll gain a bit productivity over regular ADO.NET but don't come anywhere close to LLBLGen Pro productivity.



    &gt; what's the purpose of the javaName in the schema?



    No clue, I think the blokes at ThoughtWorks reused the schema of an in house Java project.

Comments have been disabled for this content.