Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Object Persistence: The way to n-tier Nirvana

7 Dec 2006 1  
Use an agile managed database framework, and feel you've finally reached programming heaven.

This article is in the Product Showcase section for our sponsors at CodeProject. These articles are intended to provide you with information on products and services that we consider useful and of value to developers.

This is a showcase review for our sponsors at CodeProject. These reviews are intended to provide you with information on products and services that we consider useful and of value to developers.

Introduction

Crainiate Objecto has been designed to make it easy to create agile n-tier data classes, using the Microsoft .NET framework version 2.0 or later, that are reusable, inheritable, and scalable. In this article, we'll see how object persistence allows you focus on writing flexible agile business object frameworks and stop worrying about database access and deployment.

What is object persistence?

Object persistence can be thought of as the smart serialization and retrieval of objects into a relational database. Using persistence, an instance of a class, such as a Person or Customer, can be seamlessly saved to an underlying database table and retrieved at any time in the future - as another instance of the class with the same property values. The easiest way to see the power of object persistence is to create and use a persistable class:

using System;
using Crainiate.Data.Persistence;

public class Person: Table
{
    private int _Id;
    private string _Name;

    [PrimaryKey(1, 1)]
    public int Id
    {
        get {return _Id;}
        set {_Id = value;}
    }

    [Column]
    public string Name
    {
        get {return _Name;}
        set {_Name = value;}
    }
}

In the example above, we create a new Person class to hold some basic details, containing some standard properties Id and Name. There are two things that make this class persistable. Firstly, the properties are decorated with PrimaryKey and Column attributes that let an underlying database know exactly how to store instances of this class in a table. Secondly, the class derives from the Table base class. The benefits of deriving the Person class from Table become clear when we look at the second code sample:

    //Insert a person

    Person person = new Person();
    person.Name = "John Smith";
    person.Insert();

    //Retrieve a person with a known Id

    person.Id = 3;
    person.Select();

The Table class provides us with SQL-like methods to let us know what we can do with the object. When we call the Insert or Update method, an underlying data provider saves the property values from the object to a table located in the database. The Select method populates the object's properties depending on the value of the Id property marked with PrimaryKey. In the example above, new primary keys are automatically created for our Person class every time it is inserted.

How does this work? Objecto uses a new technology called Managed Database Deployment. When you deploy an assembly with one or more persisted classes, a data provider connects to the chosen target database and checks the underlying schema to add or change any database table or field so that it can store instances from the latest version of the assembly - safely and without any data loss. When the Select, Insert, or Update method is called, the provider decides whether to create a new stored procedure or use an existing stored procedure to process the request.

Why is object persistence so powerful?

Object persistence combines the power and scalability of a relational database with the flexibility of a fully object-orientated data design. Your class defines the structure of your data, and encapsulates the business logic - the data provider manages the structure and access to the underlying database automatically. This allows you to focus on implementing business rules, and not on the code that makes the application work across the different tiers of a solution.

The normal rules of inheritance apply to persisted objects. When creating derived classes, data is linked together seamlessly populating a single object instance. This promotes reuse of business logic through the use of common classes, with more specialized classes inheriting the base functionality - without worrying about changing the underlying database. Objecto will create a managed normalized database design, complete with indexes and constraints. Changes to your object interface will be automatically deployed to the database, making your application easy to change and enhance.

The following example demonstrates the creation of a Customer class, derived from Person:

    public class Customer: Person
    {
        private float _CreditLimit;

        [Column]
        public float CreditLimit
        {
            get {return _CreditLimit;}
            set {_CreditLimit = value;}
        }
    }

The Customer class inherits the existing Person structure and functionality, and can be used wherever the Person class is used in the application, with the additional CreditLimit available for use where new functionality is required. When a derived class is inserted, updated or selected the underlying data provider will take care of the underlying stored procedure to modify the corresponding data structure automatically. You do not need access to the source code to inherit from a persisted object - in this way a third party can enhance your data driven application without having to understand the underlying database structure.

Querying persisted classes: object reuse meets set theory

A relational database is geared towards providing a set of results, often by combining the common information contained in two separate tables into one result set. Objecto includes classes to work with collections of persisted objects. Continuing the SQL-like naming convention, the Generic Query class acts as an object-orientated interface to a database query.

To return all the Customer instances in our database with a CreditLimit > 500, we create a new Customer Query object:

    Query<Customer> query = new Query<Customer>(); 
    PropertyInfo prop = typeof(Customer).GetProperty("CreditLimit");
    Condition condition = new Condition(prop, 500);
    query.Where.Add(condition);

    //Set the database context and execute the query

    query.Context = Context; 
    query.Execute();

    //Loop through the customer results

    foreach (Customer customer in query.Results)
    {
        //Process customer here

    }

The Where collection contains the condition information determining which object instances to return when the Execute method is called. To view the results, simply iterate through the Results property collection. There are no datasets or XML mapping files required, the Results property will return a collection of Customer object instances.

What if all the properties from the entire object instance are not required? The Generic View class can be used to create other classes that contain only a subset of the full object's properties. In a high volume environment, a DataReader can be used to process the results of a query directly, without creating an object for each record.

The Query class is powerful enough to be joined to any other query using the Join method. In the next code sample, a CustomerAddress query is joined to an Address query, and only the instances common to each query are returned.

    Query<CustomerAddress> query1 = new Query<CustomerAddress>();
    Query<Address> query2 = new Query<Address>(); 

    PropertyInfo propFrom = typeof(CustomerAddress).GetProperty("AddressId");
    PropertyInfo propTo = typeof(Address).GetProperty("Id");

    query1.Join(query2, propFrom, propTo);

    //Set the database context and execute the query

    query.Context = Context;
    query.Execute();

The Address query contains results only where there are matching address IDs for all persisted CustomerAddress and Address objects. Each query contains a Results collection containing the relevant object instances.

With this approach, specific query logic can be encapsulated into a new Query class and joined to as many other Query instances as your data provider will allow. A Query's columns and conditions can be modified at runtime providing much greater flexibility - a unique query signature ensures that stored procedures are created dynamically and reused whenever possible.

What makes Objecto different from other solutions?

Objecto is geared towards the development of new business layer classes. It's important to note that it is a component framework, not a developer tool. The logic to persist your objects travels with the application, your application can be modified and enhanced by other developers without the original source code, XML mapping files, or development tools. In addition, you can deliver application code to the customer without worrying about database setup or deployment. No more scripts to create databases, and no more hassles trying to re-synchronise different database schemas between development and production systems.

Objecto has been written from the ground up for access via a service oriented architecture, or within a corporate network using .NET Remoting. The Enterprise version of Objecto includes a Remoting Provider to make assemblies containing business objects available through remoting, without the complexities and technical challenges normally associated with the .NET remoting namespace. Client activated objects, stateful or singlecall server activated objects are supported, providing the ability to scale out across multiple servers in a cluster.

Finally, Objecto allows you to code your entire application in the environment developers love best - Microsoft Visual Studio 2005. Because you define the structure of your data in one place only, and because the data provider manages the data schema and data access code for you, you will feel you've finally reached programming heaven.

Evaluate Objecto

Objecto Standard edition is totally free for developers and there are no runtime royalties. Objecto is supported through the Crainiate Community forums, or by purchasing a support plan. The download below includes a programmer's guide and comprehensive reference file.

About Crainiate

Crainiate is committed to building high-quality, feature-rich, easy to use components for developers using the Microsoft .NET framework. We offer powerful and innovative products by combining our love for technology with our creative spirit and our deep understanding of Internet and Windows based development. You can visit our website here.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here