Click here to Skip to main content
Click here to Skip to main content
Go to top

A complete guide to object oriented application development using MyGeneration Framework and Visual Studio C# .NET

, 22 Aug 2014
Rate this:
Please Sign up or sign in to vote.
A Complete Guide to develop aplication using MyGeneration code genration framework. We will develop a Meeting Room Booking web application in this Article.

Introduction  

In this article I will be explaining steps involved in developing Microsoft.net web application (ASP.Net C# in this case) based on MyGeneration code generation platform. I will be developing a sample application along the way using a small MS SQL 2008 express database. Although I am using Web application and Microsoft SQL server for this article but the solution is suitable for MySQL and other UI types such as Windows, Console apps. On the top of all I am confident for this approach as I have used this on bigger projects in commercial applications and are happily working. 

Part 1 - Understanding Application Requirements

Understanding requirements 

This is one of the most important aspects of software development. It’s as important as diagnosing of any illness for a doctor before starting any treatment. Once you get the requirements right the development becomes more visible to you. I am not going to spend whole day on this as it’s a vast area and you can find plenty of articles, books etc on web or in libraries. The main reason to mention this was just to highlight the importance of requirements gathering.  

Sample application in this Article - Meeting Room Booking System

Along with the tutorial we will be developing web based application for managing in house Meeting Room bookings within a company. To keep it simple and clean we will not go too fancy on functionality in interest of time and usability.    

 Requirements of our application  

  • Web based application accessible over the private intranet network. 
  • List Rooms , Room types and Room Bookings  
  • Allow add/Edit/Delete Room, Room types & Bookings
  •  Store Names & Email addresses of attendees for each booking 
  • Send reminder and cancellation notifications to attendees  
  • Since we have assumed that application is only available internally so anyone can access or amend booking details.    

Part 2 - MyGeneration Framework

My generation Framework is an open source template driven code generation software. Once you configured your templates according to your requirements then the rest of your application development becomes really easy and you can save valuable time and eliminate human errors. For more details on this framework please follow the links below. It’s really important to understand the framework before you can easily get around the rest of this article.   

MyGeneration Download Link  

Quick reference guide to MyGeneration Framework

General Tutorials & Articles

Useful MySQL & .NET Articles

I hope you have got a very good Idea after following the above links and article. So In part 3 we will jump onto the business end of programming but before that lets configure the templates to our needs so that we can generate the code we need.       

 

MyGeneration Templates Configuration 

I have shipped pre-configured templates that will work with MS SQL 2008 and C#.Net 4.0. Should also work with higher versions of .Net framework but I have not tested with any other .Net framework version. Templates are provided to download at the links above. You should put these unzipped files under C:/Programe Files/Mygeneration13/ so that it will become easier to browse when you work with Mygeneration client. MyGeneration client will look at this directory every time you try to open a template. These template files are saved with .vbgen extension.   

For your information I have downloaded these templates from MyGeneration a while ago and modified to make themwork with C#.Net 4.0 and MS SQL 2008. I have added some additional code generation methods such as generic list creation to use with LINQ, Listing column names etc. Feel free to modify them to your needs and please share them with the world if you find any better approach.  

Setting Connection Strings in MyGeneration Client 

MyGeneration client can be used with multiple connections and you can save as many connections as you like. Just select the one you need to work with and click on save button on very top right corner. This will be the database in current context for creating all the code using required templates.  

Part 3 - Application Development  

Deciding Application Architecture  

In this part we will develop a real world application discussed earlier. Application architecture is a crucial step when it comes to application development. Architecture should be easily understandable by other programmers as well. In this case we have the application problem domain and requirements. We are really developing a very simple application in this case but we will demonstrate the multi-tier approach when we say multi-tier application that means we will be separating out Data, business Logic and presentation layers. In our case we will separate out the application in following layers.  

  • Data Layer or Database     
  • Data Access Layer   
  • Business Logic Layer 
  • Utility Layer  - (Note this layer is not used but included in the source code project)
  • GUI Layer (Windows or Web) 
  • Base Framework – You don’t really need to create this as this is shipped with article. You can either add it as a project reference or direct DLL reference to the projects in your solution.   

Data Layer  

As stated earlier in this article we will be using MS SQL server 2008 express version as our database engine. (You can use MySQL as well but in that case you will need to use MySQL Templates to generate code as explained later in this article). For sake of simplicity we will keep the Data model very simple.  As you can see the model below we will have only four tables to manage our bookings.  

  • RoomType: This table will store all possible room types within the company. 
  • Room: Table that holds the room data.
  • Booking: This table will contain the data about booking Date & time etc.  
  • RoomAttendee: Stores attendees details for each booking.

Creating Stored Procedures  

We will use MyGen_Template_SQL_StoredProcs.vbgen template to create stored procedures. Open Mygeneration software client and then choose the configured template for creating stored procedures.

 

Select all the tables under our Database "RoomData" as you can see the image above. Once you have the generated SQL scripts you can then run it directly in MS SQL IDE using Management studio or use Visual stiudio if you prefer to do DB tasks within application platform. In most cases I prefer to directly copy the SQL script from MyGeneration output to MS SQL Management studio and hit F5.   

Note: You should never manually modify or rename these stored procedures as these will be recreated when you use this template again and also stored procedures are used as it is in Data Access layer. Should you need any customised SQL scripts in your DB you should clearly isolate them from these auto generated scripts.

Completed Data model should look like similar to the below..

Once you have the Stored procedures created then we have our data model completed for this application. The next step would be to develop application its self.   

Visual Studio solution 

To Turn the conceptual model into a practical shape lets begin with creating the follwing Projects within the Visual studio solution. As explained earlier in the Achitecture section of this article we will separate out our solution in 5 different layers each layer typically is a project as shown below. 

MyGeneration.doodads_2005 - (C#.Net Class Library) The base library shipped with the source. You don’t really need to modify this for any project unless you need to extend it further.  

RoomBooking.DAL - (C#.Net Class Library) - Data Access Layer - Project that contains Abstract classes which are auto created by code generation. Please note you must NOT modify these classes directly as code generation will always overwrite them. You must consume these classes in the Business Logic layer using inheritance.  

RoomBooking.BLL - (C#.Net Class Library) - Business Logic Layer - Project that contains the classes which are inherited from data Access layer. This is your primary working Area project. Please note these classes will not be overwritten by code generation so you can be fearless to write your custom methods in these classes.  

RoomBooking.Util - (C#.Net Library) - Project that contains utility or helper classes such as code for sending email, Read XML file etc. The reason for using this as a separate project is so that it can be consumed by any other project in the solution if needed.  

RoomBookingUI - (ASP.Net C# Web Project) - This is our User Interface. We will use ASP.net web application which is provided by Microsoft Visual Studio. The business stuff should happen on the above discussed layers. The interface should only be used for web elements and consume the intelligent work done by other layers. Draw your full attention to make it look good and quick responsive web application.  

 

Data Access Layer  

As explained in above part this project will contain the abstract classes. To create these classes open MyGeneration application. Open template by Browse to the templates directory and select MyGen_Template_CSharp_SQL_dOOdads_AbstractClass.  Click Run (Play button) or hit F5. Once your connection string is set to the correct database then you will see the dialogue as below.  

 

Output File Path: This must be your DAL project as explained earlier. You can put these classes under sub folders as well if you wish.   

 

Namespace: Namespace for the classes. (Usually a class Library name). It’s up to you to change it but recommended to leave it to the default project name as its the deafult Visual studio behaviour.

Select the database and tables for which you wish to create classes. I recommend to leave the Prefix the file with an underscore ticked as this will clearly isolate abstract classes (Data Access layer) to the Concrete classes (Business Logic Layer). Click ok and you should have the created classes in your project directory. Refresh solution or use add existing items to the project and add these classes manually to the DAL project. 

You should not touch any class manually in this project as these will be overwritten when you use the above template again.   

If you wish to sneak through the code, Below is the created class for RoomType table.  As you can see the class is ready to be consumed with all the required methods & properties available out of the box.  

/*
'===============================================================================
'  Generated From - MyGen_Template_CSharp_SQL_dOOdads_AbstractClass.vbgen
' 
'  Author: Gurdeep Singh
'  Email: gurdeeptoor@yahoo.ie
'  
'  ** IMPORTANT  ** 
'  How to Generate your stored procedures:
' 
'  SQL        = SQL_StoredProcs.vbgen
'  ACCESS     = Access_StoredProcs.vbgen
'  ORACLE     = Oracle_StoredProcs.vbgen
'  FIREBIRD   = FirebirdStoredProcs.vbgen
'  POSTGRESQL = PostgreSQL_StoredProcs.vbgen
'
'  The supporting base class SqlClientEntity is in the Architecture directory in "dOOdads".
'  
'  This object is 'abstract' which means you need to inherit from it to be able
'  to instantiate it.  This is very easilly done. You can override properties and
'  methods in your derived class, this allows you to regenerate this class at any
'  time and not worry about overwriting custom code. 
'
'  NEVER EDIT THIS FILE.
'
'  public class YourObject :  _YourObject
'  {
'
'  }
'
'===============================================================================
*/

// Generated by MyGeneration Version # (1.3.1.1)

using System;
using System.Data;
using System.Data.SqlClient;
using System.Collections;
using System.Collections.Specialized;
using MyGeneration.dOOdads;
using System.Collections.Generic;

namespace RoomBooking.DAL
{
    public abstract class _RoomType : SqlClientEntity
    {
        public _RoomType()
        {
            this.QuerySource = "RoomType";
            this.MappingName = "RoomType";

        }

        public List<string> ColumnsNamesList()
        {
            List<string> ColList = new List<string>();
            ColList.Add("RoomTypeID");
            ColList.Add("RoomTypeName");
            ColList.Add("RoomTypeDesc");
            ColList.Add("Active");

            return ColList;
        }

        //=================================================================
        //  public Overrides void AddNew()
        //=================================================================
        //
        //=================================================================
        public override void AddNew()
        {
            base.AddNew();
        }

        public override void FlushData()
        {
            this._whereClause = null;
            this._aggregateClause = null;
            base.FlushData();
        }

        //=================================================================
        //  	public Function LoadAll() As Boolean
        //=================================================================
        //  Loads all of the records in the database, and sets the currentRow to the first row
        //=================================================================
        public bool LoadAll()
        {
            ListDictionary parameters = null;

            return base.LoadFromSql("[" + this.SchemaStoredProcedure + 
                    "proc_RoomTypeLoadAll]", parameters);
        }

        //=================================================================
        // public Overridable Function LoadByPrimaryKey()  As Boolean
        //=================================================================
        //  Loads a single row of via the primary key
        //=================================================================
        public virtual bool LoadByPrimaryKey(int RoomTypeID)
        {
            ListDictionary parameters = new ListDictionary();
            parameters.Add(Parameters.RoomTypeID, RoomTypeID);


            return base.LoadFromSql("[" + this.SchemaStoredProcedure + 
                    "proc_RoomTypeLoadByPrimaryKey]", parameters);
        }

        #region Parameters
        protected class Parameters
        {

            public static SqlParameter RoomTypeID
            {
                get
                {
                    return new SqlParameter("@RoomTypeID", SqlDbType.Int, 0);
                }
            }

            public static SqlParameter RoomTypeName
            {
                get
                {
                    return new SqlParameter("@RoomTypeName", SqlDbType.NVarChar, 50);
                }
            }

            public static SqlParameter RoomTypeDesc
            {
                get
                {
                    return new SqlParameter("@RoomTypeDesc", SqlDbType.NVarChar, 100);
                }
            }

            public static SqlParameter Active
            {
                get
                {
                    return new SqlParameter("@Active", SqlDbType.Bit, 0);
                }
            }

        }
        #endregion

        #region ColumnNames
        public class ColumnNames
        {
            public const string RoomTypeID = "RoomTypeID";
            public const string RoomTypeName = "RoomTypeName";
            public const string RoomTypeDesc = "RoomTypeDesc";
            public const string Active = "Active";

            static public string ToPropertyName(string columnName)
            {
                if (ht == null)
                {
                    ht = new Hashtable();

                    ht[RoomTypeID] = _RoomType.PropertyNames.RoomTypeID;
                    ht[RoomTypeName] = _RoomType.PropertyNames.RoomTypeName;
                    ht[RoomTypeDesc] = _RoomType.PropertyNames.RoomTypeDesc;
                    ht[Active] = _RoomType.PropertyNames.Active;

                }
                return (string)ht[columnName];
            }

            static private Hashtable ht = null;
        }
        #endregion

        #region PropertyNames
        public class PropertyNames
        {
            public const string RoomTypeID = "RoomTypeID";
            public const string RoomTypeName = "RoomTypeName";
            public const string RoomTypeDesc = "RoomTypeDesc";
            public const string Active = "Active";

            static public string ToColumnName(string propertyName)
            {
                if (ht == null)
                {
                    ht = new Hashtable();

                    ht[RoomTypeID] = _RoomType.ColumnNames.RoomTypeID;
                    ht[RoomTypeName] = _RoomType.ColumnNames.RoomTypeName;
                    ht[RoomTypeDesc] = _RoomType.ColumnNames.RoomTypeDesc;
                    ht[Active] = _RoomType.ColumnNames.Active;

                }
                return (string)ht[propertyName];
            }

            static private Hashtable ht = null;
        }
        #endregion

        #region StringPropertyNames
        public class StringPropertyNames
        {
            public const string RoomTypeID = "s_RoomTypeID";
            public const string RoomTypeName = "s_RoomTypeName";
            public const string RoomTypeDesc = "s_RoomTypeDesc";
            public const string Active = "s_Active";

        }
        #endregion

        #region Properties

        public virtual int RoomTypeID
        {
            get
            {
                return base.Getint(ColumnNames.RoomTypeID);
            }
            set
            {
                base.Setint(ColumnNames.RoomTypeID, value);
            }
        }

        public virtual string RoomTypeName
        {
            get
            {
                return base.Getstring(ColumnNames.RoomTypeName);
            }
            set
            {
                base.Setstring(ColumnNames.RoomTypeName, value);
            }
        }

        public virtual string RoomTypeDesc
        {
            get
            {
                return base.Getstring(ColumnNames.RoomTypeDesc);
            }
            set
            {
                base.Setstring(ColumnNames.RoomTypeDesc, value);
            }
        }

        public virtual bool Active
        {
            get
            {
                return base.Getbool(ColumnNames.Active);
            }
            set
            {
                base.Setbool(ColumnNames.Active, value);
            }
        }


        #endregion

        #region String Properties

        public virtual string s_RoomTypeID
        {
            get
            {
                return this.IsColumnNull(ColumnNames.RoomTypeID) ? 
                  string.Empty : base.GetintAsString(ColumnNames.RoomTypeID);
            }
            set
            {
                if (string.Empty == value)
                    this.SetColumnNull(ColumnNames.RoomTypeID);
                else
                    this.RoomTypeID = base.SetintAsString(ColumnNames.RoomTypeID, value);
            }
        }

        public virtual string s_RoomTypeName
        {
            get
            {
                return this.IsColumnNull(ColumnNames.RoomTypeName) ? 
                  string.Empty : base.GetstringAsString(ColumnNames.RoomTypeName);
            }
            set
            {
                if (string.Empty == value)
                    this.SetColumnNull(ColumnNames.RoomTypeName);
                else
                    this.RoomTypeName = base.SetstringAsString(ColumnNames.RoomTypeName, value);
            }
        }

        public virtual string s_RoomTypeDesc
        {
            get
            {
                return this.IsColumnNull(ColumnNames.RoomTypeDesc) ? 
                  string.Empty : base.GetstringAsString(ColumnNames.RoomTypeDesc);
            }
            set
            {
                if (string.Empty == value)
                    this.SetColumnNull(ColumnNames.RoomTypeDesc);
                else
                    this.RoomTypeDesc = base.SetstringAsString(ColumnNames.RoomTypeDesc, value);
            }
        }

        public virtual string s_Active
        {
            get
            {
                return this.IsColumnNull(ColumnNames.Active) ? 
                  string.Empty : base.GetboolAsString(ColumnNames.Active);
            }
            set
            {
                if (string.Empty == value)
                    this.SetColumnNull(ColumnNames.Active);
                else
                    this.Active = base.SetboolAsString(ColumnNames.Active, value);
            }
        }


        #endregion

        #region Where Clause
        public class WhereClause
        {
            public WhereClause(BusinessEntity entity)
            {
                this._entity = entity;
            }

            public TearOffWhereParameter TearOff
            {
                get
                {
                    if (_tearOff == null)
                    {
                        _tearOff = new TearOffWhereParameter(this);
                    }

                    return _tearOff;
                }
            }

            #region WhereParameter TearOffs
            public class TearOffWhereParameter
            {
                public TearOffWhereParameter(WhereClause clause)
                {
                    this._clause = clause;
                }


                public WhereParameter RoomTypeID
                {
                    get
                    {
                        WhereParameter where = 
                          new WhereParameter(ColumnNames.RoomTypeID, Parameters.RoomTypeID);
                        this._clause._entity.Query.AddWhereParameter(where);
                        return where;
                    }
                }

                public WhereParameter RoomTypeName
                {
                    get
                    {
                        WhereParameter where = 
                          new WhereParameter(ColumnNames.RoomTypeName, Parameters.RoomTypeName);
                        this._clause._entity.Query.AddWhereParameter(where);
                        return where;
                    }
                }

                public WhereParameter RoomTypeDesc
                {
                    get
                    {
                        WhereParameter where = 
                          new WhereParameter(ColumnNames.RoomTypeDesc, Parameters.RoomTypeDesc);
                        this._clause._entity.Query.AddWhereParameter(where);
                        return where;
                    }
                }

                public WhereParameter Active
                {
                    get
                    {
                        WhereParameter where = new WhereParameter(ColumnNames.Active, Parameters.Active);
                        this._clause._entity.Query.AddWhereParameter(where);
                        return where;
                    }
                }


                private WhereClause _clause;
            }
            #endregion

            public WhereParameter RoomTypeID
            {
                get
                {
                    if (_RoomTypeID_W == null)
                    {
                        _RoomTypeID_W = TearOff.RoomTypeID;
                    }
                    return _RoomTypeID_W;
                }
            }

            public WhereParameter RoomTypeName
            {
                get
                {
                    if (_RoomTypeName_W == null)
                    {
                        _RoomTypeName_W = TearOff.RoomTypeName;
                    }
                    return _RoomTypeName_W;
                }
            }

            public WhereParameter RoomTypeDesc
            {
                get
                {
                    if (_RoomTypeDesc_W == null)
                    {
                        _RoomTypeDesc_W = TearOff.RoomTypeDesc;
                    }
                    return _RoomTypeDesc_W;
                }
            }

            public WhereParameter Active
            {
                get
                {
                    if (_Active_W == null)
                    {
                        _Active_W = TearOff.Active;
                    }
                    return _Active_W;
                }
            }

            private WhereParameter _RoomTypeID_W = null;
            private WhereParameter _RoomTypeName_W = null;
            private WhereParameter _RoomTypeDesc_W = null;
            private WhereParameter _Active_W = null;

            public void WhereClauseReset()
            {
                _RoomTypeID_W = null;
                _RoomTypeName_W = null;
                _RoomTypeDesc_W = null;
                _Active_W = null;

                this._entity.Query.FlushWhereParameters();

            }

            private BusinessEntity _entity;
            private TearOffWhereParameter _tearOff;

        }

        public WhereClause Where
        {
            get
            {
                if (_whereClause == null)
                {
                    _whereClause = new WhereClause(this);
                }

                return _whereClause;
            }
        }

        private WhereClause _whereClause = null;
        #endregion

        #region Aggregate Clause
        public class AggregateClause
        {
            public AggregateClause(BusinessEntity entity)
            {
                this._entity = entity;
            }

            public TearOffAggregateParameter TearOff
            {
                get
                {
                    if (_tearOff == null)
                    {
                        _tearOff = new TearOffAggregateParameter(this);
                    }

                    return _tearOff;
                }
            }

            #region AggregateParameter TearOffs
            public class TearOffAggregateParameter
            {
                public TearOffAggregateParameter(AggregateClause clause)
                {
                    this._clause = clause;
                }


                public AggregateParameter RoomTypeID
                {
                    get
                    {
                        AggregateParameter aggregate = 
                          new AggregateParameter(ColumnNames.RoomTypeID, Parameters.RoomTypeID);
                        this._clause._entity.Query.AddAggregateParameter(aggregate);
                        return aggregate;
                    }
                }

                public AggregateParameter RoomTypeName
                {
                    get
                    {
                        AggregateParameter aggregate = 
                          new AggregateParameter(ColumnNames.RoomTypeName, Parameters.RoomTypeName);
                        this._clause._entity.Query.AddAggregateParameter(aggregate);
                        return aggregate;
                    }
                }

                public AggregateParameter RoomTypeDesc
                {
                    get
                    {
                        AggregateParameter aggregate = 
                          new AggregateParameter(ColumnNames.RoomTypeDesc, Parameters.RoomTypeDesc);
                        this._clause._entity.Query.AddAggregateParameter(aggregate);
                        return aggregate;
                    }
                }

                public AggregateParameter Active
                {
                    get
                    {
                        AggregateParameter aggregate = 
                          new AggregateParameter(ColumnNames.Active, Parameters.Active);
                        this._clause._entity.Query.AddAggregateParameter(aggregate);
                        return aggregate;
                    }
                }


                private AggregateClause _clause;
            }
            #endregion

            public AggregateParameter RoomTypeID
            {
                get
                {
                    if (_RoomTypeID_W == null)
                    {
                        _RoomTypeID_W = TearOff.RoomTypeID;
                    }
                    return _RoomTypeID_W;
                }
            }

            public AggregateParameter RoomTypeName
            {
                get
                {
                    if (_RoomTypeName_W == null)
                    {
                        _RoomTypeName_W = TearOff.RoomTypeName;
                    }
                    return _RoomTypeName_W;
                }
            }

            public AggregateParameter RoomTypeDesc
            {
                get
                {
                    if (_RoomTypeDesc_W == null)
                    {
                        _RoomTypeDesc_W = TearOff.RoomTypeDesc;
                    }
                    return _RoomTypeDesc_W;
                }
            }

            public AggregateParameter Active
            {
                get
                {
                    if (_Active_W == null)
                    {
                        _Active_W = TearOff.Active;
                    }
                    return _Active_W;
                }
            }

            private AggregateParameter _RoomTypeID_W = null;
            private AggregateParameter _RoomTypeName_W = null;
            private AggregateParameter _RoomTypeDesc_W = null;
            private AggregateParameter _Active_W = null;

            public void AggregateClauseReset()
            {
                _RoomTypeID_W = null;
                _RoomTypeName_W = null;
                _RoomTypeDesc_W = null;
                _Active_W = null;

                this._entity.Query.FlushAggregateParameters();

            }

            private BusinessEntity _entity;
            private TearOffAggregateParameter _tearOff;

        }

        public AggregateClause Aggregate
        {
            get
            {
                if (_aggregateClause == null)
                {
                    _aggregateClause = new AggregateClause(this);
                }

                return _aggregateClause;
            }
        }

        private AggregateClause _aggregateClause = null;
        #endregion

        protected override IDbCommand GetInsertCommand()
        {

            SqlCommand cmd = new SqlCommand();
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.CommandText = "[" + this.SchemaStoredProcedure + "proc_RoomTypeInsert]";

            CreateParameters(cmd);

            SqlParameter p;
            p = cmd.Parameters[Parameters.RoomTypeID.ParameterName];
            p.Direction = ParameterDirection.Output;

            return cmd;
        }

        protected override IDbCommand GetUpdateCommand()
        {

            SqlCommand cmd = new SqlCommand();
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.CommandText = "[" + this.SchemaStoredProcedure + "proc_RoomTypeUpdate]";

            CreateParameters(cmd);

            return cmd;
        }

        protected override IDbCommand GetDeleteCommand()
        {

            SqlCommand cmd = new SqlCommand();
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.CommandText = "[" + this.SchemaStoredProcedure + "proc_RoomTypeDelete]";

            SqlParameter p;
            p = cmd.Parameters.Add(Parameters.RoomTypeID);
            p.SourceColumn = ColumnNames.RoomTypeID;
            p.SourceVersion = DataRowVersion.Current;


            return cmd;
        }

        private IDbCommand CreateParameters(SqlCommand cmd)
        {
            SqlParameter p;

            p = cmd.Parameters.Add(Parameters.RoomTypeID);
            p.SourceColumn = ColumnNames.RoomTypeID;
            p.SourceVersion = DataRowVersion.Current;

            p = cmd.Parameters.Add(Parameters.RoomTypeName);
            p.SourceColumn = ColumnNames.RoomTypeName;
            p.SourceVersion = DataRowVersion.Current;

            p = cmd.Parameters.Add(Parameters.RoomTypeDesc);
            p.SourceColumn = ColumnNames.RoomTypeDesc;
            p.SourceVersion = DataRowVersion.Current;

            p = cmd.Parameters.Add(Parameters.Active);
            p.SourceColumn = ColumnNames.Active;
            p.SourceVersion = DataRowVersion.Current;


            return cmd;
        }
    }
}

Below is the class diagram for Data access layer 

Business Logic Layer

Now that you have the Data & Data Access layers done. Next part is the Business Logic where you will actually start write some code by your hand. But to get you started with these classes there's template that will create the classes with some of the out of box methods for you. To create these classes select MyGen_Template_CSharp_SQL_dOOdads_ConcreteClass from the templates directory and then run this template. You will see the dialogue like the one shown below.  

 

Output file path: Use the BAL project directory to place your concrete classes. (Note: This may be very same as the DAL project if you have decided to embed both Data Access & Business Logic layers in a single project.)

Business Namespace: Name space to be used by classes under Business Logic layer. (Usually the project name). 

Data Access Namespace: Name space used by the Data Access Layer Classes. 

Select Tables and hit OK. Import these created classes into your Business Logic Layer (RoomBooking.BLL) project. If any of the classes exists already this template will not overwrite the old classes. You can extend these classes the way you wish. Below is the example of Class Room i.e. Room Table in our database. Note the inheritance from its Data access counterpart _Room. Also Note the custom method that I have manually wrote in this class to get the RoomType object for this class.  

//Generator Framework: MyGeneration Version: # (1.3.1.1)
//Author: Gurdeep Singh 
//Email:  gurdeeptoor@yahoo.ie

using System;
using System.Data;
using System.Data.SqlClient;
using System.Collections;
using System.Collections.Specialized;
using System.Collections.Generic;
using System.Linq;
using MyGeneration.dOOdads;
using RoomBooking.DAL;

namespace RoomBooking.BLL
{
    public class Room : _Room
    {


        //Search Type Enum
        public enum SearchType
        {
            Equal,
            StartsWith,
            EndsWith,
            Wild,
        }

        //Sort Direction Type Enum
        public enum SortDirection
        {
            Asc,
            Desc,
        }

        /// <summary>
        /// Construct the class with passing Dynamic connection string.
        /// </summary>
        /// <param name="ConnectionString">Connection string 
        ///             from web.config or app.config file</param>
        public Room(string ConnectionString)
        {
            this.ConnectionString = ConnectionString;
        }

        //Load all with applying sort
        public bool LoadAll(bool ApplySort)
        {
            bool _Loadall = true;

            _Loadall = this.LoadAll();

            if (_Loadall && ApplySort)
            {
                this.Sort = Room.ColumnNames.RoomName;
            }

            return _Loadall;
        }

        /// <summary>
        /// Load by a Single Column Value
        /// </summary>
        /// <param name="ColumnName">Name of Column</param>
        /// <param name="ColumnValue">Value to be Searched</param>
        /// <param name="SearchType">Search Type Enum</param>
        /// <returns></returns>
        public bool LoadByColumnValue(string ColumnName, string ColumnValue, SearchType SearchTypeOption)
        {
            bool _Loadall = true;

            _Loadall = this.LoadAll();

            if (_Loadall)
            {
                switch (SearchTypeOption)
                {
                    case SearchType.Equal:
                        this.Filter = ColumnName + "='" + ColumnValue + "'";
                        return _Loadall;

                    case SearchType.StartsWith:
                        this.Filter = ColumnName + " Like '%" + ColumnValue + "'";
                        return _Loadall;

                    case SearchType.EndsWith:
                        this.Filter = ColumnName + " Like '" + ColumnValue + "%'";
                        return _Loadall;

                    case SearchType.Wild:
                        this.Filter = ColumnName + " Like '%" + ColumnValue + "%'";
                        return _Loadall;
                }
            }

            return _Loadall;
        }


        /// <summary>
        /// ConvertToList : You must load the object before converting to list.
        /// </summary>
        /// <param name="InputObject">Input Object pre populated</param>
        /// <returns>generic list of Room collection</returns>
        public List<Room> ConvertToList(Room InputObject)
        {
            List<Room> List = new List<Room>();
            List<DataRow> dlist = new List<DataRow>();
            dlist = InputObject.DefaultView.ToTable().AsEnumerable().ToList<DataRow>();

            foreach (DataRow row in dlist)
            {
                Room InsObject = new Room(this.ConnectionString);
                InsObject.AddNew();
                //This method below is in BusinessEntity class in MyGeneration framework
                DataRowToObject(InsObject, row);
                List.Add(InsObject);
            }

            return List;
        }

        /// <summary>
        /// ConvertToList : You must load the object before converting to list.
        /// </summary>
        /// <param name="InputObject">Input Object pre populated</param>
        /// <param name="sort">Column to Sort</param>
        /// <param name="sortcolumn">Sort direction</param>
        /// <param name="page">Page number to display</param>
        /// <param name="numRows">Total number of records to be displayed on page</param>
        /// <returns>Sorted generic collection of Continent limited to one page data</returns>
        public List<Room> ConvertToList(Room InputObject, 
          string sortcolumn, SortDirection sortDir, int page, int numRows)
        {
            List<Room> List = new List<Room>();
            //Sor this object first
            if (sortcolumn != null)
                InputObject.Sort = string.Format("{0} {1}", sortcolumn, sortDir.ToString());

            List = ConvertToList(InputObject);
            return List.AsQueryable().Skip((page - 1) * numRows).Take(numRows).ToList<Room>();
        }

        /// <summary>
        /// Get RoomType for this Room
        /// </summary>
        /// <returns></returns>
        public RoomType GetRoomType()
        {
            RoomType RoomType = new RoomType(this.ConnectionString);
            RoomType.LoadByPrimaryKey(this.RoomTypeID);
            return RoomType;
        }

    }
} 

Below is the class diagram for Business Logic layer 

Utility Layer

This project is there for convenience and to keep the things simple we have not used in this example. You can include any reusable method you wish in this project for example sending email code we could have placed here.  

UI Layer - ASP.NET Web application 

At this stage you are a web designer more than an application developer. In a bigger team this part should have been done in parallel to the above layers. The design concept in normal cases will be agreed in advance with the end users. Anyway let’s assume you are the only one working and nothing has been done yet for this apart from the requirements.   

NOTE: You can use any methodology or approach for designing the web application such as MVC etc. For this article we will stick to the usual Microsoft ASP.NET web application using C#.Net.  

I am a big fan of user controls when it comes to web application development. Since it’s a very simple application we only need three major parts i.e. Room, RoomType and Bookings (Thinking bjects here). So as you can assume Room & Rooms types are usual list and edit stuff. So let’s start with listing & editing RoomTypes.

Listing/Editing RoomTypes:  For listing RoomTypes we will use Datagridview on a web form. On load this page will display all the room types available in the system. To achieve this by code we will use the List object of Business Logic layer i.e. List of RoomTypes and simply bind it to the Gridview. See the code snippet below...  

private void LoadRoomTypeList()
{
    RoomType RoomType = new RoomType(AppGlobals.ConnectionStrings.cstrRoomData);
    RoomType.LoadAll(true);
    gvRoomType.DataSource = RoomType.DefaultView;
    gvRoomType.DataBind();
}

Now by looking at the above code the obvious question you would have that what is "Appglobals.ConnectionStrings.ctrRoomdata". It’s simply a connection string that is passed to the business object.  Each business object created in Business Logic layer takes this as its initialization parameter. AppGloabls is a static class used for storing such static values to be used in the application. You can imagine how many times we have to use this connection strings and it may not be a good idea to hard code it everywhere.

Below is the list of Room types displayed on a web form.  

To edit we will use the user control and make it available on the page as a pop up using Ajax Popup extender. User control is simply a tabular form. Note that this user control raises two custom events SaveClicked and cancelClicked. This is done in order to handle Ajax popup extender since popup extender can only be controlled (at least easily) from the page where it was created.  

Handling popup extender from user control: Every time user clicks on Save or Cancel, we need to hide the popup and show the main page. We will create two custom events on user Control and handle them on the main page.  

public EventHandler SaveClicked;
public EventHandler CancelClicked; 

protected void btnSave_Click(object sender, EventArgs e)
{
    //validate the input...
    Validate();

    RoomType RoomType = new RoomType(AppGlobals.ConnectionStrings.cstrRoomData);

    if (Page.IsValid)
    {
        if (lblRoomTypeID.Text == "0")
        {
            RoomType.AddNew();
            RoomType.Active = true;
            RoomType.RoomTypeName = txtRoomTypeName.Text;
            RoomType.RoomTypeDesc = txtRoomTypeDesc.Text;
            RoomType.RoomTypeID = 0;
            RoomType.Save();
        }
        else
        {
            //load the copy from DB
            RoomType.LoadByPrimaryKey(Convert.ToInt32(lblRoomTypeID.Text));

            //Check if description was changed
            if (RoomType.RoomTypeDesc != txtRoomTypeDesc.Text || 
                        RoomType.RoomTypeName != txtRoomTypeName.Text)
            {
                RoomType.RoomTypeName = txtRoomTypeName.Text;
                RoomType.RoomTypeDesc = txtRoomTypeDesc.Text;
                RoomType.Save();
            }
        }

        //raise the event
        SaveClicked(sender, e);
    }

    else
    {
      
    }
}

protected void btnCancel_Click(object sender, EventArgs e)
{
    CancelClicked(sender, e);
} 

On Web form we will then register these events as below.  

//Register user control event handlers
  ucRoomTypeEdit1.SaveClicked += new EventHandler(ucRoomTypeEdit1_SaveClicked);
  ucRoomTypeEdit1.CancelClicked += new EventHandler(ucRoomTypeEdit1_CancelClicked);  

And then handle them like this to Show/Hide the Edit popup on the web form. Please Note that this approach is used throughout the application.  

protected void ucRoomTypeEdit1_SaveClicked(object sender, EventArgs e)
{
pnlRoomTypeEdit.Visible = false;
lblInfo.Visible = false;
MPE.Hide();
LoadRoomTypeList();
}

protected void ucRoomTypeEdit1_CancelClicked(object sender, EventArgs e)
{
 pnlRoomTypeEdit.Visible = false;
 lblInfo.Visible = false;
 MPE.Hide();
}

Listing/Editing Rooms: We will save time here as it’s not needed to explain it again. This is very same as RoomType apart from the object is different.  

Listing/Editing Bookings: The most important part of our application’s web layer. We need to provide an easy and efficient way to handle bookings. If you list the bookings like the above objects it’s not really a user friendly way to show the bookings. It’s a bit of challenge to develop some custom control to handle all this. So why not use Google to find something which can handle all this nice features. After spending not too long but good few hours I came up with the following that can fit well into our requirements.

http://www.daypilot.org/calendar.html   

For the purpose of this article I have used the full featured trial version of Daypilot calendar control. This gives us the out of box functionality to handle on screen edit, delete and create Calendar entries and provides a nice look to the end users. Also you can style the control in your own way.   

Databindings are very same as the gridview. We will split the booking display per room so that user can select he room and date range to find or create the appropriate bookings. Below is the code snippet to bind the bookings data to calendar control.  

int RoomID = ddlRoom.SelectedValue.Length > 0 ? Convert.ToInt32(ddlRoom.SelectedValue) : 0;
int Days = Convert.ToInt32(rdWeekView.SelectedValue) * 5;

Booking Booking = new Booking(AppGlobals.ConnectionStrings.cstrRoomData);
DayPilotCalendar1.Days = Days;
Booking.LoadByColumnValue(Booking.ColumnNames.RoomID, RoomID.ToString(), RoomBooking.BLL.Booking.SearchType.Equal);
DayPilotCalendar1.DataSource = Booking.DefaultView;
DayPilotCalendar1.DataBind();
DayPilotCalendar1.UpdateWithMessage(LoadingMessage); 

Above is the completed booking form. Calendar control server side events are used to handle booking Creation, deletion and modification. Few code snippets below from this form. 

Whenever user selects an existing booking we need to popup the booking edit form. 

protected void DayPilotCalendar1_EventSelect(object sender, DayPilotEventArgs e)
{
    int SelectedBookingID = Convert.ToInt32(DayPilotCalendar1.SelectedEvents[0].Value);

    //pop-up            
    MPE.Show();
    pnlBookingEdit.Visible = true;
    ucBookingEdit1.LoadData(SelectedBookingID);
}  

Apart from creating a booking from new button user also has an option to drag the mouse along the cells and we need to handle this to create the new booking. Below is the code to handle TimeRangeSelected event and show the new Booking form in a popup.  Note we prevent past date bookings.

protected void DayPilotCalendar1_TimeRangeSelected(object sender, TimeRangeSelectedEventArgs e)
{
    if (e.Start.Date > DateTime.Today.AddDays(-1))
    {
        //pop-up
        MPE.Show();
        pnlBookingEdit.Visible = true;
        ucBookingEdit1.CreateNew(Convert.ToInt32(ddlRoom.SelectedValue), e.Start, e.End, false);
    }
    else
    {
        LoadBookings("New booking for Past date not possible");
    }
}

Handling Attendees and Notify Meeting Cancellations & Reschedules: Attendees are tied to each booking. As you can see these are handled in the booking edit form. Every time booking is Created, Moved or Deleted attendees are notified by sending an email. Please download the source code for full details. Below is the code for sending emails and that is in AppGlobals static class in the web application. 

public static void SendMeetingEmail(Room Room, Booking RoomBooking, 
           List<RoomAttendee> RoomAttendeeList, string MeetingAction)
{
    int ToEmailCount;
    int DocCount;
    string _EmailRecepients = string.Empty;

    foreach (RoomAttendee roomAttendee in RoomAttendeeList)
    {
        if (_EmailRecepients.Length > 0)
            _EmailRecepients = string.Format("{0};{1}", _EmailRecepients, roomAttendee.Email);
        else
            _EmailRecepients = roomAttendee.Email;
    }

    StringBuilder sb = new StringBuilder();
    sb.AppendLine(string.Format("Hi, <br/><br/> Please Note - " + 
      "Meeting detailed below has been <b>{0}</b> by {1}", 
      MeetingAction, RoomBooking.BookedBy));
    sb.AppendLine("<br/><br/>");
    sb.AppendLine(string.Format("Description: {0}", 
      RoomBooking.BookingNotes.Remove(RoomBooking.BookingNotes.LastIndexOf("-"))));
      //Note we are taking away the user initials
    sb.AppendLine("<br/>");
    sb.AppendLine(string.Format("Location: {0}", Room.RoomName));
    sb.AppendLine("<br/>");
    sb.AppendLine(string.Format("Start Time: {0}", RoomBooking.BookDateFrom));
    sb.AppendLine("<br/>");
    sb.AppendLine(string.Format("End Time: {0}", RoomBooking.BookDateTo));
    sb.AppendLine("<br/>");

    sb.AppendLine("<br/>");
    sb.AppendLine(string.Format("People in this meeting : {0}", RoomAttendeeList.Count));
    sb.AppendLine("<table border='1'>");
    foreach (RoomAttendee roomAttendee in RoomAttendeeList)
    {
        sb.AppendLine(string.Format("<tr><td>{0} {1} {2}" + 
          "</td></tr>", roomAttendee.Title, 
          roomAttendee.FirstName, roomAttendee.LastName));
    }
    sb.AppendLine("</table>");
    sb.AppendLine("<br/>");
    sb.AppendLine("<br/>");
    sb.AppendLine("<i>System generated email, Please DO NOT Reply !!</i>");
    sb.AppendLine("<br/><br/>");
    sb.AppendLine("Best Regards,");
    sb.AppendLine("<br/>");
    sb.AppendLine("Admin");
    sb.AppendLine("<br/>");
    sb.AppendLine("Meeting Room Booking System");

    if (_EmailRecepients.Trim().Length > 0)
    {
        SendEmail(_EmailRecepients,
                  string.Format("Meeting Room Booking System - Meeting {0}", MeetingAction),
                  sb.ToString(),
                  string.Empty,
                   out ToEmailCount,
                  out DocCount);
    }
}

Part 4 - My2ndGeneration: Future code generation 

MyGeneration has recently gone web based. I haven’t had a chance to look at this in details. It looks like the future of code generation. More details on this link.   

As soon as I get my head around this new platform I will post another article here So stay in touch...!!  

Conclusion       

To sum up this is one of the many available approaches to develop object oriented application. As any new platform takes time to learn MyGerenation platform is no different. It needs some of your time to get your head around it. But for sure this is practical and I have used it in many projects. It has saved us a lot of development time and the power of templates has made it even more interesting.  Please do get back with any Feedback and vote for this article if you think it can be of any use to the world out there.  

Happy coding...!!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Gurdeep Singh Toor
Software Developer (Senior)
Ireland Ireland
Gurdeep is graduated from National College of Ireland. He has been involved in application development since 2006 & has experience in software solutions across multiple business sectors such as Transportation, Company Registry & Telecoms. He is always keen to learn and keep up to date with the Software development world. Gurdeep is currently working as a Software Developer in Dublin (Ireland) in a Telecoms Company.

Apart from I.T. he is a big fan of Music & love to play Cricket. He is an active member of a local Cricket Club (Adamstown Cricket Club - www.adamstowncricketclub.ie).

Comments and Discussions

 
GeneralMy vote of 5 PinmemberBurak Ozdiken23-Aug-14 0:32 
GeneralRe: My vote of 5 PinmemberGurdeep Singh Toor18-Sep-14 4:41 
GeneralMy vote of 5 PinmemberHumayun Kabir Mamun19-Aug-14 2:04 
GeneralRe: My vote of 5 PinmemberGurdeep Singh Toor18-Sep-14 4:41 
Suggestionstored procedures Pinmemberdotnetangel20-Aug-13 3:52 
GeneralRe: stored procedures PinmemberGurdeep Singh Toor20-Aug-13 6:26 
QuestionProblem with mygeneration Pinmemberoorja19-Aug-13 6:46 
AnswerRe: Problem with mygeneration PinmemberGurdeep Singh Toor19-Aug-13 7:09 
GeneralRe: Problem with mygeneration Pinmemberoorja19-Aug-13 19:11 
GeneralMy vote of 5 PinmemberHumayun Kabir Mamun15-Aug-13 20:48 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140926.1 | Last Updated 22 Aug 2014
Article Copyright 2013 by Gurdeep Singh Toor
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid