Sep 21 2006

Creating a BLL - howto part 6

Posted by admin under In practice

Our project so far might indeed be functional, but we do have some major design flaws to fix. It is not so good to do all our database work directly from our ASPX files - and since we will eventually need to support MySQL as well as MSSQL, that would be a nightmare to fix if we had to change every aspx file (erhhm, ok, we only have two aspx files in our fictive project, but you get the point).

Our next step is to create a BLL library. Our ASPX files should not work against datasets/datatables but instead classes and collections - and we start it off by adding a new project to our solution:

Now we have two projects - one web project and one class library project.


Lets look at how we handled databinding before (default.aspx):



    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            GridView1.DataSource = Microsoft.ApplicationBlocks.Data.SqlHelper.ExecuteDataset(ConfigurationManager.ConnectionStrings["MainConn"].ToString(),
                CommandType.StoredProcedure, "cust_ListCustomers").Tables[0];
            GridView1.DataBind();
        }
    }




We want it to look like:



    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            CustomerClasses.CustomerCollection oColl = new CustomerClasses.CustomerCollection();
            oColl.OpenAll();
            GridView1.DataSource = oColl;
            GridView1.DataBind();
        }
    }







Now how you create your BLL classes is up to you. I recommend some sort of O/R code generator (I use my own to automatically get code for private variables, properties and database calls with automatic SqlParameter generation) but here I have just handcoded it:



    public class Customer
    {
        private string m_strCustname;
        private long m_lId;
        public long Id
        {
            get { return m_lId; }
            set { m_lId = value; }
        }

        public string Custname
        {
            get { return m_strCustname; }
            set { m_strCustname = value; }
        }

        public bool Open( long lId )
        {
            SqlParameter[] paramsToSP = new SqlParameter[1];
            paramsToSP[0] = new SqlParameter("@id", SqlDbType.Int);
            paramsToSP[0].Value = Convert.ToInt32(Request["id"]);
            DataTable dt = Microsoft.ApplicationBlocks.Data.SqlHelper.ExecuteDataset(ConfigurationManager.ConnectionStrings["MainConn"].ToString(),
                CommandType.StoredProcedure, "cust_OpenCust", paramsToSP).Tables[0];

            if (dt.Rows.Count == 0)
                return false;
            InitFromRow(dt.Rows[0]);
        }

        public void InitFromRow(DataRow row)
        {
            m_lId = Convert.ToInt64( row["id"] );
            m_strCustname = Convert.ToString(row["custname"]);
        }
    }






As you can see we will now have properties to work against instead of row["fieldname"]. See the use of a special function InitFromRow to map the datarow column names to properties. While it might look not necessery at the moment it soon will - we will be able to use it from our Collection class as well.

The collection


I have decided to use generics - which pretty much ties the specific solution to ASP.NET 2.0. However, the structure is the same if you are creating a ASP.NET 1.x solution - just make your collection inherit from CollectionBase instead.



    public class CustomerCollection : System.Collections.Generic.List<Customer>
    {
        public void OpenAll()
        {
            DataSet ds = Microsoft.ApplicationBlocks.Data.SqlHelper.ExecuteDataset(
                System.Configuration.ConfigurationManager.ConnectionStrings["MainConn"].ToString(),
                CommandType.StoredProcedure, "cust_ListCustomers");

            foreach (DataRow row in ds.Tables[0].Rows )
            {
                Customer oCust = new Customer();
                oCust.InitFromRow( row );
                Add(oCust);
            }
        }

    }






And that's it! Now we just change all places in our ASPX files, lets look at how the code in default.aspx GridView1_RowDataBound looks:



    protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
    {
        if (e.Row.RowType == DataControlRowType.DataRow)
        {
            CustomerClasses.Customer oCust = e.Row.DataItem as CustomerClasses.Customer;
            Label lblCustName = e.Row.FindControl("lblCustName") as Label;
            if (lblCustName != null)
                lblCustName.Text = oCust.Custname;
            HyperLink hlEdit = e.Row.FindControl("hlEdit") as HyperLink;
            if (hlEdit != null)
                hlEdit.NavigateUrl = "editcust.aspx?id=" +  oCust.Id.ToString();
        }
    }

Now the DataItems are Customer objects instead of DataViewRows.


This article does not have a download - it will be available in next step instead.