We don't use ORM. We are using ado.net, data reader, stored procedures and business object. Maybe you have some better suggestion? Enterprise Lybrary or orm?
Perhaps I misunderstood - it sounded like you are defining a separate BO per stored procedure eg if your sproc is called GetPeople, you have a one to one mapping with a GetPeople object. If you have another sproc called GetPeopleByStatus, you would create
an object called getPeopleByStatus. Now that would not be a good design. There's nothing wrong with working with ADO.NET directly.
You should never need to use a DataTable object in ASP.NET, especially in a data access layer. You should populate the object directly from the data reader. That's a lot more efficient. In Imars article, he has method per data access class - one for the
contact, one for the address and so on, that is responsible for "hydrating" obejcts. They look like this:
private static Person FillDataRecord(IDataRecord record){
var person = new Person {
Id = record.GetInt32(record.GetOrdinal("Id")),
FirstName = record.GetString(record.GetOrdinal("FirstName")),
LastName = record.GetString(record.GetOrdinal("LastName")),
DateOfBirth = record.GetDateTime(record.GetOrdinal("DateOfBirth")),
Email = record.GetString(record.GetOrdinal("Email"))
};
return person;
}
You can have a number of sproc wrapper methods use this method. For example a FindPersonById sproc would map to a FindPersonById method that would use the FillDataRecord method to return a person object:
public static Person FindById(int id) {
var query = @"sproc_FindPersonById";
Person person = null;
using (var conn = new SqlConnection(GetConnectionString())) {
using (var cmd = new SqlCommand(query, conn)) {
cmd.Parameters.AddWithValue("@id", id);
conn.Open();
using (var rdr = cmd.ExecuteReader()) {
if (rdr.Read()) {
person = FillDataRecord(rdr);
}
}
}
return person;
}
}
You might have a GetAllPeople sproc. You should return a List<Person> from the wrapper method:
public static List<Person> GetAllPeople() {
var query = @"sproc_GetAllPeople";
List<Person> people = null;
using (var conn = new SqlConnection(GetConnectionString())) {
using (var cmd = new SqlCommand(query, conn)) {
conn.Open();
using (var rdr = cmd.ExecuteReader()) {
if (rdr.HasRows) {
people = new List<Person>();
while (rdr.Read()) {
people.Add(FillDataRecord(rdr));
}
}
}
}
}
return people;
}
Then if you have a GetPeopleByCategory or a GetPeopleByStatus sproc, you would still return a List<Person> from the methods you create to manage those.
Logging, validation, authntication and so on are generally known as "cross cutting concerns" as they cut across the logical boundaries of the application. Recommended practice is that each of those concerns will exists as a library, but that they will be
made available across the traditional (BO, BLL, DA) layers as required. You wouldn't have a DAL logging library
and a BLL logging library for example. The logging library should be generic enough that it can be plugged into both layers.
only_you
Member
56 Points
110 Posts
Naming of business object
Nov 08, 2012 08:03 PM|LINK
Hi,
business object in application is mapped one on one with stored procedure. Does business object should have the same name like a stored procedure?
Mikesdotnett...
All-Star
155649 Points
19987 Posts
Moderator
MVP
Re: Naming of business object
Nov 08, 2012 09:14 PM|LINK
Business objects should be named according to what they represent in the real world, like Order, Customer, Animal, Gift, Policy etc.
That is rarely a good design.
Web Pages CMS | My Site | Twitter
only_you
Member
56 Points
110 Posts
Re: Naming of business object
Nov 08, 2012 10:17 PM|LINK
We don't use ORM. We are using ado.net, data reader, stored procedures and business object. Maybe you have some better suggestion? Enterprise Lybrary or orm?
Mikesdotnett...
All-Star
155649 Points
19987 Posts
Moderator
MVP
Re: Naming of business object
Nov 09, 2012 05:57 AM|LINK
Perhaps I misunderstood - it sounded like you are defining a separate BO per stored procedure eg if your sproc is called GetPeople, you have a one to one mapping with a GetPeople object. If you have another sproc called GetPeopleByStatus, you would create an object called getPeopleByStatus. Now that would not be a good design. There's nothing wrong with working with ADO.NET directly.
Web Pages CMS | My Site | Twitter
only_you
Member
56 Points
110 Posts
Re: Naming of business object
Nov 09, 2012 06:21 AM|LINK
Exactly, separate BO per stored procedure. Ok, I learned something from your post :-) Another question, how I would have done a better solution...
What BO should have? In my solution, it's properties mapped on stored procedures, and constructor with DataReader parameter.
public class Test { #region PrivateFields private int _id = 0; private string _name = string.Empty; private string _type = string.Empty; #endregion PrivateFields #region Properties public int Id { get { return _id; } set { _id = value; } } public string Name { get { return _name; } set { _name = value; } } public string Type { get { return _type; } set { _type = value; } } #endregion Properties #region Constructors public Test() { } public Test(SqlDataReader reader) { LoadFromReader(reader); } #endregion Contructor #region Methods private void LoadFromReader(SqlDataReader reader) { if (reader != null && !reader.IsClosed) { DataTable dt = reader.GetSchemaTable(); if (dt.Select("ColumnName='" + "Id" + "'").Length > 0) if (!reader.IsDBNull(reader.GetOrdinal("Id"))) Id= reader.GetInt32(reader.GetOrdinal("Id")); if (dt.Select("ColumnName='" + "Name" + "'").Length > 0) if (!reader.IsDBNull(reader.GetOrdinal("Name"))) Name= reader.GetString(reader.GetOrdinal("Name")); if (dt.Select("ColumnName='" + "Type" + "'").Length > 0) if (!reader.IsDBNull(reader.GetOrdinal("Type"))) Type= reader.GetString(reader.GetOrdinal("Type")); } } #endregion Methods }Mikesdotnett...
All-Star
155649 Points
19987 Posts
Moderator
MVP
Re: Naming of business object
Nov 09, 2012 07:27 AM|LINK
There's a really clear article that details a basic approach to this here: http://imar.spaanjaars.com/416/building-layered-web-applications-with-microsoft-aspnet-20-part-1
You should never need to use a DataTable object in ASP.NET, especially in a data access layer. You should populate the object directly from the data reader. That's a lot more efficient. In Imars article, he has method per data access class - one for the contact, one for the address and so on, that is responsible for "hydrating" obejcts. They look like this:
private static Person FillDataRecord(IDataRecord record){ var person = new Person { Id = record.GetInt32(record.GetOrdinal("Id")), FirstName = record.GetString(record.GetOrdinal("FirstName")), LastName = record.GetString(record.GetOrdinal("LastName")), DateOfBirth = record.GetDateTime(record.GetOrdinal("DateOfBirth")), Email = record.GetString(record.GetOrdinal("Email")) }; return person; }You can have a number of sproc wrapper methods use this method. For example a FindPersonById sproc would map to a FindPersonById method that would use the FillDataRecord method to return a person object:
public static Person FindById(int id) { var query = @"sproc_FindPersonById"; Person person = null; using (var conn = new SqlConnection(GetConnectionString())) { using (var cmd = new SqlCommand(query, conn)) { cmd.Parameters.AddWithValue("@id", id); conn.Open(); using (var rdr = cmd.ExecuteReader()) { if (rdr.Read()) { person = FillDataRecord(rdr); } } } return person; } }You might have a GetAllPeople sproc. You should return a List<Person> from the wrapper method:
public static List<Person> GetAllPeople() { var query = @"sproc_GetAllPeople"; List<Person> people = null; using (var conn = new SqlConnection(GetConnectionString())) { using (var cmd = new SqlCommand(query, conn)) { conn.Open(); using (var rdr = cmd.ExecuteReader()) { if (rdr.HasRows) { people = new List<Person>(); while (rdr.Read()) { people.Add(FillDataRecord(rdr)); } } } } } return people; }Then if you have a GetPeopleByCategory or a GetPeopleByStatus sproc, you would still return a List<Person> from the methods you create to manage those.
Web Pages CMS | My Site | Twitter
only_you
Member
56 Points
110 Posts
Re: Naming of business object
Nov 09, 2012 07:46 AM|LINK
Thanks a lot. Yet another question :-)
Does every layer in app (BO,DAL,BLL) should also have one common class library for Exception, maybe logging, and other common things?
Mikesdotnett...
All-Star
155649 Points
19987 Posts
Moderator
MVP
Re: Naming of business object
Nov 09, 2012 08:05 AM|LINK
Logging, validation, authntication and so on are generally known as "cross cutting concerns" as they cut across the logical boundaries of the application. Recommended practice is that each of those concerns will exists as a library, but that they will be made available across the traditional (BO, BLL, DA) layers as required. You wouldn't have a DAL logging library and a BLL logging library for example. The logging library should be generic enough that it can be plugged into both layers.
Web Pages CMS | My Site | Twitter