Freitag, 22. Juni 2007

How to use CSLA objects with NHibernate

Instead of using the ADO.NET data reader as in the reference implementation to fill a CSLA object with data one can as well use an O/R mapper tool like NHibernate and fetch the data through this object layer.

We have the following diagram


where Category, Product and ProductNote are the NHibernate data objects and ProductBO, ProductNotesBO and ProductNoteBO are the CSLA business objects.

The root CSLA object ProductBO

Typicall code might look as follows:

private void DataPortal_Fetch(Criteria criteria)
{
using (ISession session = SessionFactory.Current.OpenSession())
{
Product item = session.Get<Product>(criteria.ProductId);
_productId = item.ProductID;
_version = item.Version;
_productName = item.ProductName;
_categoryId = item.Category.CategoryID;


//******** Get Child Collection(s)
_notes = ProductNotesBO.GetProductNotesBO(item.Notes);
}
}


On the other hand we also have to add or update the data in the database. Code might look as follows

[Transactional(TransactionalTypes.TransactionScope)]
protected override void DataPortal_Insert()
{
InsertOrUpdate();
}


[Transactional(TransactionalTypes.TransactionScope)]
protected override void DataPortal_Update()
{
InsertOrUpdate();
}


private void InsertOrUpdate()
{
using (ISession session = SessionFactory.Current.OpenSession())
{
Product item = new Product();
item.ProductID = _productId;
item.Version = _version;
item.ProductName = _productName;


//***************** This is how to solve Lookup-Type relations
// (Category is a Lookup Table for Product related tasks)
item.Category = new Category();
item.Category.CategoryID = _categoryId;
item.Category.Version = 999;


//***************** Only update the item if needed (new or dirty)!
if (base.IsDirty)
{
session.SaveOrUpdate(item);


if (IsNew)
{
_productId = item.ProductID; // get new (generated) ID!
_version = item.Version; // and new Version number
}
MarkOld();
}


//***************** Update Child Collection(s)
_notes.Update(session, item);
session.Flush();
}
}


To delete an object from the database one might use code as follows

[Transactional(TransactionalTypes.TransactionScope)]
protected override void DataPortal_DeleteSelf()
{
DataPortal_Delete(new Criteria(_productId));
MarkNew();
}


[Transactional(TransactionalTypes.TransactionScope)]
private void DataPortal_Delete(Criteria criteria)
{
using (ISession session = SessionFactory.Current.OpenSession())
{
//*************** First delete children (if allowed!!!)
session.Delete("from ProductNote n where n.Product.ProductID=:id",
criteria.ProductId, NHibernateUtil.Int32);


//*************** And now delete the item itself!
session.Delete("from Product p where p.ProductID = :id",
criteria.ProductId, NHibernateUtil.Int32);


session.Flush();
}
}


Note that we are using the Transactional attribute to make the insert, update and delete operations atomic.

The CSLA child collection ProductNotesBO

The factory methods of the child collection

public static ProductNotesBO NewProductNotesBO()
{
return new ProductNotesBO();
}


public static ProductNotesBO GetProductNotesBO(
IEnumerable; list)
{
return new ProductNotesBO(list);
}


private ProductNotesBO()
{
MarkAsChild();
}


private ProductNotesBO(IEnumerable list)
{
Fetch(list);
MarkAsChild();
}

Code used to fetch data

private void Fetch(IEnumerable list)
{
RaiseListChangedEvents = false;


foreach (ProductNote item in list)
{
Add(ProductNoteBO.GetProductNoteBO(item));
}


RaiseListChangedEvents = true;
}


Code used to add, update and delete data

internal void Update(ISession session, Product parent)
{
RaiseListChangedEvents = false;


//------------------- Delete Removed Children ---------------------
if (DeletedList.Count > 0)
{
StringBuilder ids = new StringBuilder();
foreach (ProductNoteBO item in DeletedList)
{
if (ids.Length > 0) ids.Append(",");
ids.Append(item.ProductNoteId);
}
string sql = string.Format(
"from ProductNote n where n.ProductNoteID in ({0})",
ids);
session.Delete(sql);


DeletedList.Clear();
}


//------------------- Add or Update Children ----------------------
foreach (ProductNoteBO item in this)
if (item.IsNew)
item.Insert(session, parent);
else
item.Update(session, parent);


RaiseListChangedEvents = true;
}


The CSLA child object ProductNoteBO

The factory methods of the child business object

public static ProductNoteBO NewProductNoteBO(bool isChild)
{
return new ProductNoteBO(isChild);
}


public static ProductNoteBO GetProductNoteBO(ProductNote item)
{
return new ProductNoteBO(item);
}


public static ProductNoteBO GetProductNoteBO(int productNoteId)
{
return DataPortal.Fetch(new Criteria(productNoteId));
}


public static void DeleteProductNoteBO(int productNoteId)
{
DataPortal.Delete(new Criteria(productNoteId));
}


private ProductNoteBO()
{ }


private ProductNoteBO(bool isChild)
{
if(isChild) MarkAsChild();
}


private ProductNoteBO(ProductNote item)
{
Fetch(item);
MarkAsChild();
}


Here we have introduced a isChild parameter which gives us the possibility to use this business object either as child object or as root object.

Code used to fetch data

private void Fetch(ProductNote item)
{
_productNoteId = item.ProductNoteID;
_version = item.Version;
_productNoteText = item.ProductNoteText;
MarkOld();
}


Code used to add and update data

internal void Insert(ISession session, Product parent)
{
InsertOrUpdate(parent, session);
}


internal void Update(ISession session, Product parent)
{
InsertOrUpdate(parent, session);
}


private void InsertOrUpdate(Product parent, ISession session)
{
if (base.IsDirty)
{
ProductNote item = new ProductNote();
item.ProductNoteID = _productNoteId;
item.Version = _version;
item.ProductNoteText = _productNoteText;
item.Product = parent; // set parent
session.SaveOrUpdate(item);


if (IsNew)
{
_productNoteId = item.ProductNoteID; // load generated ID!
_version = item.Version;
}


MarkOld();
}
}

Donnerstag, 21. Juni 2007

Optimize NHibernate Queries

Some times I want to load an instance of an object which has one or several child collections. Usually I design my object relational mapping to use lazy loading by default. The result of this is that when loading a single instance of a object and accessing its child collections NHibernate spits out at least one additional query per collection. So I have many roudtrips to the server.

Fortuately NHibernate 1.2 offers the new possbility to create a "Multi-Query". The result is (at least for the SQL Server) that only ONE single roundtrip is made to the server and several resultsets are returned.

Let's make an example. We have a Category entity which has two child collections of type Product and Note. That is, any category object can have a list of associated Products and Notes. If I want to display all details of a specific Category on a view, then I have to load the details of the category object and the details of any of the associated products and notes objects. I have at least 3 queries to send to the database.

Now with the following syntax we reduce the roundtrips to the database needed to exactly one:

IList firstResultList = (IList) session.CreateMultiQuery()
.Add("from Category cat left join fetch cat.Products where cat.CategoryID = :id")
.Add("from Category cat left join fetch cat.Notes where cat.CategoryID = :id")
.SetInt32("id", id)
.List()[0];
Category item = (Category) firstResultList[0];

Technorati Tags: , ,

Freitag, 15. Juni 2007

One-to-one mapping and Lazy loading

Often we have the following situation: An entity has some attributes that are important and often accessed and then it has some other attributes that are either rarely used or their content is large in size (e.g. a photo or a document). In such situations it is common to split the entity into two tables. One table containing the important attributes and the other the remaining ones. A typical example is table 'Person' and table 'PersonDetails'. These tables are relatet by a 1 to 0..1 relation. That is a person can have person details but doesn't need to. On the other hand 'person details' always belong to a 'person'.

Question: How can we instruct NHibernate and/or ActiveRecord to give us such a relation. We want to have the possibility to load a list of persons WITHOUT loading also their corresponding details. The details should ONLY be loaded when we really access them. That is called 'Lazy Loading'.

Just using a one-to-one relation doesn't work! We have to use a 'trick' and use a combination of a many-to-one and a one-to-one relation. This solves our problem.

NHibernate

Let us look at the code:

namespace NHibernateTest
{
    public class Person
    {
        private int _personID;
        private string _lastName;
        private string _firstName;
        private PersonPhoto _photo;

        public virtual int PersonID
        {
            get { return _personID; }
            set { _personID = value; }
        }

        public virtual PersonPhoto Photo
        {
            get { return _photo; }
            set { _photo = value; }
        }

        public virtual string LastName
        {
            get { return _lastName; }
            set { _lastName = value; }
        }

        public virtual string FirstName
        {
            get { return _firstName; }
            set { _firstName = value; }
        }
    }

    public class PersonPhoto
    {
        private int _personID;
        private byte[] _photo;
        private Person _owner;

        public virtual int PersonID
        {
            get { return _personID; }
            set { _personID = value; }
        }

        public virtual Person Owner
        {
            get { return _owner; }
            set { _owner = value; }
        }

        public virtual byte[] Photo
        {
            get { return _photo; }
            set { _photo = value; }
        }
    }
}

and now at the NHibernate mapping file(s)

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="NHibernateTest" namespace="NHibernateTest">
  <class name="Person" >
    <id name="PersonID" type="Int32">
      <generator class="identity" />
    </id>
    <property name="LastName" type="String" length="50" />
    <property name="FirstName" type="String" length="50" />
    <many-to-one name="Photo" class="PersonPhoto" />
  </class>

  <class name="PersonPhoto">
    <id name="PersonID" type="Int32">
      <generator class="foreign">
        <param name="property">Owner</param>
      </generator>
    </id>
    <property name="Photo" type="BinaryBlob" />
    <one-to-one name="Owner" class="Person" constrained="true" />
  </class>
</hibernate-mapping>

Note:

  • on the "parent" side (Person) we have the many-to-one relation which points to PersonPhoto.
  • on the "child" side (PersonPhoto) the primary key (PersonID) is the same as on the "parent" side. Thus the value must be "inherited" from the parent. This is the reason to use "foreign" as generator class. The <param> tag just points to the Property from which NHibernate can get this PK value, in our case the property is called Owner (which is the Person who owns this photo).
  • on the "child" side we have the one-to-one relation which points to Person.
  • the one-to-one relation sets constrained=true since the person details belongs to a person (a person MUST exists).

ActiveRecord

We can define the same behaviour in ActiveRecord. Here I choose a similar sample as above, a one-to-one relation between a Car and its CarPhoto. Code explains better than many words, thus:

[ActiveRecord("Car", Lazy = true)]
public class Car : ActiveRecordBase<Car>
{
    private Guid _CarID;
    private CarPhoto _photo;
    private string _make;

    [PrimaryKey(PrimaryKeyType.Guid, "CarID", ColumnType = "Guid")]
    public virtual Guid CarID
    {
        get { return _CarID; }
        set { _CarID = value; }
    }

    [BelongsTo(Column = "CarID", Unique = true)]
    public virtual CarPhoto Photo
    {
        get { return _photo; }
        set { _photo = value; }
    }

    [Property(ColumnType = "String", Length = 50)]
    public virtual string Make
    {
        get { return _make; }
        set { _make = value; }
    }
}

[ActiveRecord("CarPhoto", Lazy = true)]
public class CarPhoto : ActiveRecordBase<CarPhoto>
{
    private Guid _CarID;
    private Car _owner;
    private byte[] _photo;

    [PrimaryKey(PrimaryKeyType.Foreign, "CarID", ColumnType = "Guid")]
    public virtual Guid CarID
    {
        get { return _CarID; }
        set { _CarID = value; }
    }

    [OneToOne(Constrained = true)]
    public virtual Car Owner
    {
        get { return _owner; }
        set { _owner = value; }
    }

    [Property(ColumnType = "BinaryBlob", SqlType = "VARBINARY(MAX)")]
    public virtual byte[] Photo
    {
        get { return _photo; }
        set { _photo = value; }
    }
}

Now I can happily load a list of cars and the photos are not loaded by default but only when I really access them...

Freitag, 8. Juni 2007

Prequisites for Distributed Applications

When developing any more or less complex LOB application the developer needs some decent patterns, frameworks and tools to efficiently fullfill the given task. I assemled a list of elements which I personally recommend

  • Base Framework: .NET 2.0 or 3.0
  • O/R-Mapping: NHibernate and ActiveRecords
  • IoC: Castle Windsor Container or MS ObjectBuilder
  • Testing: NUnit, MbUnit, Rhino.Mocks
  • Business Layer: CSLA
  • Smart Client: CAB, SCSF

Tools

  • VS 2005 Professional or Team Edition
  • Resharper 2.5 or higher
  • ActiveWriter Plugin for VS
  • TestDriven Plugin for VS

Patterns

  • Presentation Layer
    • MVC: Model View Controller, or
    • MVP: Model View Presenter

Processes/Design

  • Domain Driven Design (DDD)
  • Test Driven Development (TDD)
  • Behaviour Driven Development (BDD)

All the items mentioned above need some further discussion and will be covered in more details below and in my future posts.

Acronyms

First let me define the acronyms used so far:

Acronym Description
O/R-Mapping Object-Relational Mapping. A technique used to bridge the gap between the relational database and the object oriented application
IoC Inversion of Control: A technique used to instanciate, instrument and maintain objects during their life time. Especially helpful if one is developing loosely coupled applications
Unit Test
A test methodology used to test the state and behaviour of a single unit (e.g. object)
CSLA Componentized Scalable Logical Architecture. Rockford Lhotka’s CSLA .NET framework is an application development framework that helps build a powerful, maintainable business logic layer for Windows, Web and Web Services applications
MVC Model View Controller Pattern
MVP Model View Presenter Pattern
DDD Domain Driven Design
BDD Behaviour Driven Design
TDD Test Driven Developement
CAB Componentized (User Interface) Application Block
SCSF Smart Client Software Factory
LOB Line of Business (Applications)

Links, Downloads

O/R Mapping

To bridge the gap between the relational database system (RDBMS) and the object oriented application domain we choose to use NHibernate. NHibernate allows us to define mappings between objects and their corresponding tables in the database via xml mapping files. Not only can one define the mappings between objects and tables but also the relations between different objects can be mapped to the corresponding relations in the database. NHibernate supports 1 to 1, 1 to many and many to many relations. These are the most common scenarios we typically encounter in LOB.
When we use a Domain-Driven Design (DDD) NHibernate supports us with the possibility to automatically generate the necessary database schema. Developing the object model first and then derive the database schema from the object model is in our opinion a more "natural" way of implementing a "green field" application than the more "traditional" way of implementing an application where the Entity Relationship Diagram (ERD) is designed first.
When using NHibernate one immediately is looking for a way to avoid the tedious task to manually write the xml-mapping files for each object in the domain. Fortunately the Castle Project has
ActiveRecord as one of its sub-projects. ActiveRecords allows us to decorate the classes in our domain directly with Attributes instead of writing xml-mapping files. ActiveRecord is well documented and I do not want to repeat this documentation here. But I want to discuss a concrete example.
But wait! Do I really have to write my classes by hand and decorate them and its respective properties with Attibutes? Isn't there a "better" way of doing it? Yes, indeed there is: Gökhan Altinören has written a VS PlugIn which allows us to visually desing our object model. Its the
ActiveWriter PlugIn which I'll be using in the following example.
Example

  • A person has hobbies. The relation between a person and a hobby is many-to-many since a person can have many hobbies and a single hobby like swimming can be exercised by many different persons.
  • A person has assigned tasks. The relation between a person and a task is also many-to-many since a person can have many assigned tasks and a single task like "write a blog entry on topic xyz..." can be assigned to many different persons.
  • A person can blog - as I do here. A person can maintain several blogs but each blog belongs to a single person (at least in my sample). Thus the relation between person and blog is one-to-many.
  • To a person we want to be able to store a photo. Since a photo can be rather large we decide NOT to store the photo directly in the Person object but create an extra PersonPhoto object which is owned by the Person object. So as a benefit we have the possibility to only load the PersonPhoto data if really needed. The relation between a person and a photo is one-to-one.
  • A person has an address. But also e.g. a company has an address. So we decide to not make the relation between person and address as one-to-one but rather many-to-one.But the relation has a further restriction in so far that the "many" part of the relation is effectively a unique restriction since a single address cannot (in reality) be shared among different persons (or e.g. companies).

This leads us to the following design (in ActiveWriter)


Classes
For each class we have to define the mapping via the property window. Just select the corresponding class and modify the atributes similar to the example below

In the above example the mapping is between the Person class and a table also called Person which is defined in the (database) schema gns.
Note that when not defining the Table attribute NHibernate automatically takes the value of the attribute Name as the name for the underlying table.
Properties
Note that each object (or class) has a property Key. This is a value which uniquely identifies an instance of the respective type. The Key property is mapped to the primary key column in the underlying database table.
To make our application multi-user friendly I also introduced a Version property for each object. This allows us to handle any concurrent (write) access to a specific object. NHibernate offers built-in functionality for such properties.
The other properties are common properties and are all of type string except for the Photo property in the PersonPhoto class which is of type BinaryBlob.
Each Property of a class can be configured through the Properties Windows. Just activate the corresponding property in the ActiveWriter designer.
For the Version property I have set the following values

For the Key Property of the Person object I have set the following values. Note that I use Guid's for the key. One can as well use int or long.

In the Column attribute you define how the corresponding column will be called in the underlying table Person. If you don't specify a value then NHibernate will automatically take the value of the attribute Name as the column name. This fact was used for the Version property defined above.
The other properties are easy and I'll show here as an example the property Photo of the PersonPhoto class

Relations
The most interesting part are the relations among the different classes (or objects). The first time you use ActiveWriter you might be a little bit confused about the naming convention. The author of ActiveWriter is working on it and will soon provide a detailed description. Never the less let's have a look at the various relation types
One-to-One relation
Let's look at the one-to-one relation between Person and PersonPhoto. I have defined the following attributes

What does this mean? Source Constrained = True means that a photo cannot exist without a corresponding person but vice versa a person can exist without having a photo (Target Constrained = False).Target Cascade = All means that when saving or deleting a person the owned photo is automatically save or deleted too. On the other hand when I save or delete a photo the corresponding person object is not affected (Source Cascade = None).
One-to-Many relation
As an example let's have a look at the relation between Person and Blog(s).

In this example consider the "Source..." as the One-side (here the Person) and the "Target..." as the Many-side (here the Blog) of the relation.
Note:
the Target Lazy = True setting which means that I do not want to have all blogs automatically loaded when I load a person object. Only if I access the person's blog(s) NHibernate shall load the corresponding blog(s). The Property Blogs in the Person class is of type IList. This list is sorted by BlogName (see the Target Order By = BlogName)

.

.

.

.

Many-to-Many relation
Here we look at the relation between the Person and Task classes.

Any many-to-many relation needs a link table in the database. Here we define the link table to be named PersonTask and residing in the schema gns.The setting Source Lazy = True means that I do not want all tasks to be automatically loaded when I load a person. They should only be loaded when I want to access them.The other settings are more or less self-describing.








.

to be continued...