Introduction
Most
of the Software Architects want to make communication between User Interfaces, Business
objects and Data Access layer using object collections. In this tip, I want
to discuss how we can design our application.
Background
Now
a days, I am working on a very big product which has hundreds of business entity
and business object. Business objects communicate via database using entity
object and XML.
Why they want to use collection based communication is not
the scope of this article.
In
the .NET application, we receive the tabular data from the database in the object
of DataTable
or DataSet
. Before returning it to the Business object, we convert
the object of DataTable
to the collection.
First
of all, we create an Entity
class.
Public class Entity
{
public string Property1 { get; set; }
public string Property2 { get; set; }
public string Property3 { get; set; }
public string Property4 { get; set; }
}
The next step is to map the Entity
properties with the DataTable
columns.
To map business entity properties with data table columns, we
define a class which can be used like an attribute. Hence this class should be
inherited with the System.Attribute
class.
public class BusinessEntityAttribute : System.Attribute
{
public string DBFieldName { get; set; }
public object NullValue { get; set; }
public string Format { get; set; }
public BusinessEntityAttribute(string dbFieldName, string nullValue,
string format="") : base()
{
this.DBFieldName = dbFieldName;
this.NullValue = nullValue;
this.Format = format;
}
}
Now we are ready to map entity class properties and data table
columns:
public class Entity
{
[BusinessEntityAttribute("COLUMN1", "","")]
public string Property1 { get; set; }
[BusinessEntityAttribute("COLUMN2", "","")]
public string Property2 { get; set; }
[BusinessEntityAttribute("COLUMN3", "","")]
public string Property3 { get; set; }
[BusinessEntityAttribute("COLUMN4", "","")]
public string Property4 { get; set; }
}
Here
COLUMN1
is the name of a column which we get from the database.
As
you know, in .NET we store tabular data in the DataTable
object. So we have to
create a method which can take the object of DataTable
and can return the
collection of Entity
objects. Since we have hundreds of entity classes, we
must have to write a generic method which can be used for each of the entity
classes.
public static List<T> ConvertDatatableToList<T>(DataTable dataTable) where T : new()
{
List<T> list = null;
if (dataTable != null)
{
list = new List<T>();
foreach (DataRow dataRow in dataTable.Rows)
{
T businessEntityObject = new T();
PropertyInfo[] pi = businessEntityObject.GetType().GetProperties();
foreach (PropertyInfo prop in pi)
{
BusinessEntityAttribute businessObjectAttributes =
(BusinessEntityAttribute)Attribute.GetCustomAttribute(prop, typeof(BusinessEntityAttribute));
if (businessObjectAttributes != null &&
businessObjectAttributes.DBFieldName != string.Empty &&
dataTable.Columns.Contains(businessObjectAttributes.DBFieldName) &&
dataRow[businessObjectAttributes.DBFieldName] != DBNull.Value)
{
if (prop.PropertyType == typeof(DateTime) ||
prop.PropertyType == typeof(DateTime?))
{
prop.SetValue(businessEntityObject, ((DateTime)(dataRow[businessObjectAttributes.DBFieldName])), null);
}
else if (prop.PropertyType == typeof(Double) &&
!string.IsNullOrWhiteSpace(businessObjectAttributes.Format)
{
prop.SetValue(businessEntityObject, dataRow[businessObjectAttributes.DBFieldName] ==
DBNull.Value ? 0 : Math.Round(Convert.ToDouble(dataRow[businessObjectAttributes.DBFieldName]),
int.Parse(businessObjectAttributes.Format)), null);
}
else
prop.SetValue(businessEntityObject, dataRow[businessObjectAttributes.DBFieldName] ==
DBNull.Value ? businessObjectAttributes.NullValue : Convert.ChangeType
(dataRow[businessObjectAttributes.DBFieldName], prop.PropertyType), null);
}
}
list.Add(businessEntityObject);
};
}
return list;
}
So, we can use the above methods to convert DataTable
object
to Entity
collection:
List<Entity> lstEntity = ConvertDatatableToList<Entity>(dt);
Till
now, we have completed one part (receive data from the database). Next part is
we have to send back the entity object to the database ( stored procedure).
We
have to write a generic code so that we can use this code for each of the
entity classes/objects. Here, we can use XML to send the entity object to the
stored procedure. To send the entity object to the stored procedure, we have to
serialize the entity objects to prepare the XML data.
There are two ways to do this:
- We can use
Xml
attribute to define the XML element name for serialization: [Serializable]
[XmlRoot("Entity")]
public class Entity
{
[XmlElement("COLUMN1")]
[BusinessEntityAttribute("COLUMN1", "","10")]
public string Property1 { get; set; }
...
}
- In the
first approach, we use
XmlElement
attribute to define the element while
serializing entity
object. In this case, we have to add two attributes with the
same column name “COLUMN1
”. It is a little bit overhead.
public class BusinessEntityAttribute : XmlElementAttribute
{
…
}
The next and last step is to serialize the entity class/object:
XmlSerializer serializer = new XmlSerializer(typeof(Entity));
XmlSerializerNamespaces xmlNamespace = new XmlSerializerNamespaces();
xmlNamespace.Add(string.Empty, string.Empty);
StringBuilder sb = new StringBuilder();
using (XmlWriter xw = XmlWriter.Create(sb, new XmlWriterSettings() { OmitXmlDeclaration = true, Indent = true }))
{
serializer.Serialize(xw, entity, xmlNamespace);
}
Thanks and happy programming.