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:
Person person = new Person();
person.Name = "John Smith";
person.Insert();
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);
query.Context = Context;
query.Execute();
foreach (Customer customer in query.Results)
{
}
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);
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.