Generic data fetch with IDataReader [modified]
-
Hi there, I'm looking for some advise for a generic data fetch pattern for IDataReader I'm working on, as follow:
// main load
using(GenericDataReader reader = new GenericDataReader(cm.ExecuteReader()))
{
while (reader.Read())
{
orders.Add(reader.Get<Order>()); // "GetList" pattern
//return new Order(reader); // "Get" pattern
}
}// generic reader; interface implementation removed
public class GenericDataReader : IDataReader
{
// ... \\public T Get<T>(string name) { int i = \_dataReader.GetOrdinal(name); if (\_dataReader.IsDBNull(i)) return default(T); else return (T)\_dataReader.GetValue(i); } public T Get<T>() where T : ILoadable, new() { T entity = new T(); entity.Load(this, false); return entity; }
}
// All business objects must implements this interface
public interface ILoadable
{
void Load(GenericDataReader reader, bool deep);
}// Sample business object
class Order : ILoadable
{
int id;
Customer customer; // Note
DateTime orderDate;
DateTime requiredDate;
DateTime? shippedDate;
List<OrderDetail> orderDetails;public Order(){ } public Order(GenericDataReader reader) { Load(reader, true); } #region ILoadable Members public void Load(GenericDataReader reader, bool deep) { id = reader.Get<int>("OrderID"); customer = reader.Get<Customer>(); // Note orderDate = reader.Get<DateTime>("OrderDate"); requiredDate = reader.Get<DateTime>("OrderRequiredDate"); shippedDate = reader.Get<DateTime?>("OrderShippedDate"); if (deep && reader.NextResult()) { orderDetails = new List<OrderDetail>(); while (reader.Read()) { orderDetails.Add(reader.Get<OrderDetail>()); } } } #endregion
}
What do you think? Are there any major drawback with this model I'm missing? Are there any more clever way to do that? I really appreciate your time reading this. As long we come to a conclusion I'll write an article for CP with that we learned about it. TIA, Rubens EDIT: Added formatting
modified on Thursday, March 20, 2008 6:44 AM
-
Hi there, I'm looking for some advise for a generic data fetch pattern for IDataReader I'm working on, as follow:
// main load
using(GenericDataReader reader = new GenericDataReader(cm.ExecuteReader()))
{
while (reader.Read())
{
orders.Add(reader.Get<Order>()); // "GetList" pattern
//return new Order(reader); // "Get" pattern
}
}// generic reader; interface implementation removed
public class GenericDataReader : IDataReader
{
// ... \\public T Get<T>(string name) { int i = \_dataReader.GetOrdinal(name); if (\_dataReader.IsDBNull(i)) return default(T); else return (T)\_dataReader.GetValue(i); } public T Get<T>() where T : ILoadable, new() { T entity = new T(); entity.Load(this, false); return entity; }
}
// All business objects must implements this interface
public interface ILoadable
{
void Load(GenericDataReader reader, bool deep);
}// Sample business object
class Order : ILoadable
{
int id;
Customer customer; // Note
DateTime orderDate;
DateTime requiredDate;
DateTime? shippedDate;
List<OrderDetail> orderDetails;public Order(){ } public Order(GenericDataReader reader) { Load(reader, true); } #region ILoadable Members public void Load(GenericDataReader reader, bool deep) { id = reader.Get<int>("OrderID"); customer = reader.Get<Customer>(); // Note orderDate = reader.Get<DateTime>("OrderDate"); requiredDate = reader.Get<DateTime>("OrderRequiredDate"); shippedDate = reader.Get<DateTime?>("OrderShippedDate"); if (deep && reader.NextResult()) { orderDetails = new List<OrderDetail>(); while (reader.Read()) { orderDetails.Add(reader.Get<OrderDetail>()); } } } #endregion
}
What do you think? Are there any major drawback with this model I'm missing? Are there any more clever way to do that? I really appreciate your time reading this. As long we come to a conclusion I'll write an article for CP with that we learned about it. TIA, Rubens EDIT: Added formatting
modified on Thursday, March 20, 2008 6:44 AM
-
Hi, can you please edit your post and place code in <pre> and <code> like this?: <pre><code>your code</code></pre> that would really help me to at least read your code. Thank you.
Sorry Michal, here you go. ty
-
Hi there, I'm looking for some advise for a generic data fetch pattern for IDataReader I'm working on, as follow:
// main load
using(GenericDataReader reader = new GenericDataReader(cm.ExecuteReader()))
{
while (reader.Read())
{
orders.Add(reader.Get<Order>()); // "GetList" pattern
//return new Order(reader); // "Get" pattern
}
}// generic reader; interface implementation removed
public class GenericDataReader : IDataReader
{
// ... \\public T Get<T>(string name) { int i = \_dataReader.GetOrdinal(name); if (\_dataReader.IsDBNull(i)) return default(T); else return (T)\_dataReader.GetValue(i); } public T Get<T>() where T : ILoadable, new() { T entity = new T(); entity.Load(this, false); return entity; }
}
// All business objects must implements this interface
public interface ILoadable
{
void Load(GenericDataReader reader, bool deep);
}// Sample business object
class Order : ILoadable
{
int id;
Customer customer; // Note
DateTime orderDate;
DateTime requiredDate;
DateTime? shippedDate;
List<OrderDetail> orderDetails;public Order(){ } public Order(GenericDataReader reader) { Load(reader, true); } #region ILoadable Members public void Load(GenericDataReader reader, bool deep) { id = reader.Get<int>("OrderID"); customer = reader.Get<Customer>(); // Note orderDate = reader.Get<DateTime>("OrderDate"); requiredDate = reader.Get<DateTime>("OrderRequiredDate"); shippedDate = reader.Get<DateTime?>("OrderShippedDate"); if (deep && reader.NextResult()) { orderDetails = new List<OrderDetail>(); while (reader.Read()) { orderDetails.Add(reader.Get<OrderDetail>()); } } } #endregion
}
What do you think? Are there any major drawback with this model I'm missing? Are there any more clever way to do that? I really appreciate your time reading this. As long we come to a conclusion I'll write an article for CP with that we learned about it. TIA, Rubens EDIT: Added formatting
modified on Thursday, March 20, 2008 6:44 AM
I would consider two things. First would be performance of
return (T)_dataReader.GetValue(i);
, I don't know exactly how GetValue works internally but I think that it is a bit slower than type specific method like GetInt32 becase there is more type conversion stuff. Plus by using type specific Get method you would save one of your type conversionreturn **(T)**_dataReader.GetValue(i)
. Disadvantage is that you would have to use IF statement to determine which specific Get method to call. Second thought is that I'm not sure if it is a best practice to have GenericDataReader to create businness objects. In my opinion objects like data readers should just get you a data and that is it. They should not be creating any business objects. Also I think that Business object should not work directly with data reader. It has lot of other work to do anyway. So I would suggest to create some BusinessDataObject that would take care of getting data from database, using GenericDataReader. And then any business object would just use relevant BusinessDataObject to load data. -
I would consider two things. First would be performance of
return (T)_dataReader.GetValue(i);
, I don't know exactly how GetValue works internally but I think that it is a bit slower than type specific method like GetInt32 becase there is more type conversion stuff. Plus by using type specific Get method you would save one of your type conversionreturn **(T)**_dataReader.GetValue(i)
. Disadvantage is that you would have to use IF statement to determine which specific Get method to call. Second thought is that I'm not sure if it is a best practice to have GenericDataReader to create businness objects. In my opinion objects like data readers should just get you a data and that is it. They should not be creating any business objects. Also I think that Business object should not work directly with data reader. It has lot of other work to do anyway. So I would suggest to create some BusinessDataObject that would take care of getting data from database, using GenericDataReader. And then any business object would just use relevant BusinessDataObject to load data.Looking at
System.Data.OleDb
implementation through Reflector, GetInt32 and GetValue returns values based on column types, so I think both have similar performance. And, if I had to code an IF inside that generic method, I prefer to stick with current ADO.NET implementation About your second thought, I share your feelings. My main point is to define a simple pattern for data fetch, probably in a structure like Entity (get/set/read) >> Data (DAL/.executeXXX) >> Business (work with loaded data) >> and so on. Thank you for your comments, I really appreciate them. Rubens -
Looking at
System.Data.OleDb
implementation through Reflector, GetInt32 and GetValue returns values based on column types, so I think both have similar performance. And, if I had to code an IF inside that generic method, I prefer to stick with current ADO.NET implementation About your second thought, I share your feelings. My main point is to define a simple pattern for data fetch, probably in a structure like Entity (get/set/read) >> Data (DAL/.executeXXX) >> Business (work with loaded data) >> and so on. Thank you for your comments, I really appreciate them. Rubensregarding GetValue you may check this link[^]
RubensFarias wrote:
Thank you for your comments, I really appreciate them.
You are welcome. Those are just my thoughts, that may be wrong. And practical solution is often far far away from ideal design. Important thing is to get things done. I wish you luck with your project.