Introduction
Being a J2EE developer in the past and a very big fan of OOD , I started a few months ago to work in .NET. Now I have seen the .NET data persistence approach, the DataSet
s, the DataReader
s and DataAdapter
s in ADO.NET, which I consider very powerful when working with more that one record in a table, but I still like using Business Objects in my design, so I wrote a small persistence framework for .NET.
Using JDO in the past , I considered making a XML description for each BO to map it to the database tables, but I saw that a better thing would be to use .NET attributes. I have found an article on the Internet with an example of using attributes for such a purpose.
Let�s say we have a BO called User
:
public class User
{
public User(){}
private long _id;
private string _name;
private string _username;
private string _password;
public long UserID {
set{_id = value;}
get {return _id;}
}
�
}
Now let�s map in to the database:
[DBTable("Users","dbo")]
[Serializable]
public class User
{
public User(){}
private long _id;
private string _name;
private string _username;
private string _password;
[DBPrimaryKeyField("ID_User",DbType.Int16)]
[DBColumn("ID_User",DbType.Int16,false)]
public long UserID
{
set{_id = value;}
get {return _id;}
}
[DBColumn("Name",DbType.String,true)]
public string Name
{
}
[DBColumn("Username",DbType.String,false)]
public string Username
{
}
[DBColumn("Password",DbType.String,false)]
public string Password
{
}
}
We have 3 attribute classes DBTable
, DBPrimaryKey
, DBColumn
. Let�s explain what each does.
DBTable(string tableName, string databaseOwner)
maps the business object to a database table
DBPrimaryKey(string pkFieldName, DBType pkFieldType, bool isAutoIncrement)
maps the Primary
column to a BO property
DBColumn(string tableFieldName, DBType fieldType, bool allowsNulls)
maps a table column to a BO property.
Now let�s look at some things that can be made with the BO. This is done using an IPersistenceService
interface.
public interface IPersistenceService
{
object Create(Object o, Type objectType);
void Update(Object o, Type objectType);
void Delete(Object id, Type objectType);
int Count(string condition, Type objectType);
Object GetObject(Object id, Type objectType);
void LoadDataSet(DataSet dataSet, String sqlQuery);
void LoadDataSet(DataSet dataSet, String sqlQuery, String tableName);
object Create(SqlConnection con, Object o, Type objectType);
void Update(SqlConnection con,Object o, Type objectType);
void Delete(SqlConnection con,Object id, Type objectType);
int Count(SqlConnection con,string condition, Type objectType);
Object GetObject(SqlConnection con,Object id, Type objectType);
void LoadDataSet(SqlConnection con,DataSet dataSet, String sqlQuery);
void LoadDataSet(SqlConnection con,DataSet dataSet, String sqlQuery,
String tableName);
SqlConnection GetConnection();
void CloseConnection(SqlConnection con);
}
We have a factory for this interface to get an implementation. In this case the implementation is made against SQL Server in PersistenceServiceImpl
. We get an implementation:
String connectionString = ���;
IPersistenceService ps = PersistenceServiceFactory.getPS(connectionString);
Now let�s create an User
and persist it.
User u = new User();
u.Name = "Dan Bunea";
u.Password = "myusername";
u.Password = "mypassword";
long id = (long)ps.Create(u,typeof(User));
or just: (if you don�t need the ID obtained for the object)
ps.Create(u,typeof(User));
Now that we have a user in the Users
table , lets retrieve it to see how that�s done.
User U2 = (User)ps.GetObject(id,typeof(User));
Let�s update it and save the changes.
U2.Name = "Dan Bunea Updates";
U2.Password = "newusername";
U2.Password = "newpassword";
P2s.Update(U2,typeof(User));
Simple J , no? Now let�s delete it.
Ps.Delete(id,typeof(User));
l have also included some methods to load DataSet
objects easily, but also if you have more operations that need to use the same connection. Let�s say we want to make all these operations on one connection:
SqlConnection con = ps.GetConnection();
User u = new User();
u.Name = "Dan Bunea";
u.Password = "myusername";
u.Password = "mypassword";
object id = (long)ps.Create(con,u,typeof(User));
User U2 = (User)ps.GetObject(con,id,typeof(User));
U2.Name = "Dan Bunea Updates";
U2.Password = "newusername";
U2.Password = "newpassword";
P2s.Update(con,U2,typeof(User));
Ps.Delete(con,id,typeof(User));
ps.CloseConnection(con);
Let�s talk a little about performance. For each BO the user must not be concerned about INSERT
, UPDATE
, DELETE
and SELECT
(for pk) queries. They are automatically generated by the code using the attributes specified in the object. Each statement for each BO is only generated once, and then cached with it�s parameters. The next time the user performs the same operation, the query is taken from cache, also its parameters and using reflection each parameter is given a value, the query is executed.
With special thanks for those that have written other articles that helped me write this, and in the hope that this was a pleasant and useful reading , I finish my small article here.