Building an ASP.Net 4.5 Web forms application - part 2

Τhis is the second post in a series of posts on how to design and implement an ASP.Net 4.5 Web Forms store that sells posters on line.

Make sure you read the first post in the series.You can find it here.

In all these posts I am going to publish, I will change the layout. That means I will make changes to the .master,.css,.aspx files and images. In the final post I will add the whole solution so you can download everything.

Have a look at the picture below to see the new slightly changed layout

 

Now that we have made the necessary changes to the .aspx pages,the master page,the .css files and adding some more images to our site we are ready to move forward and implement the data access layer.

I will use Entity Framework 5.0 in order to create the data access layer.

Obviously I cannot go into much detail on what EF is and what it does. I will give a short introduction though.The .Net framework provides support for Object Relational Mapping through EF. So EF is a an ORM tool and it is now the main data access technology that microsoft works on. I use it quite extensively in my projects. Through EF we have many things out of the box provided for us. We have the automatic generation of SQL code.It maps relational data to strongly types objects.All the changes made to the objects in the memory are persisted in a transactional way back to the data store.

You can find in this post an example on how to use the Entity Framework to retrieve data from an SQL Server Database using the "Database/Schema First" approach.

In this approach we make all the changes at the database level and then we update the model with those changes.

In this post you can see an example on how to use the "Model First" approach when working with ASP.Net and the Entity Framework.

For this project I will use the Code First approach to build the data access layer.

The Code First approach is the more code-centric than the other two (Database First, Model First). Basically we write POCO classes and then we persist to a database using something called DBContext.

Code First relies on DbContext. We create 2,3 classes (e.g Person,Product) with properties and then these classes interact with the DbContext class and we can create a new database based upon our POCOS classes and have tables generated from those classes.We do not have an .edmx file in this approach.By using this approach we can write much easier unit tests.

DbContext is a new context class and is smaller,lightweight wrapper for the main context class which is ObjectContext (Schema First and Model First).

Let's implement our POCO classes

1) Launch Visual Studio and open your solution where your project lives

2) Create a new folder. Name it DAL or any other name you think it is appropriate.We will place in there our entity classes

3) Obviously you must include EF in your solution. The good news is that EF is included in any ASP.Net Web Forms Application. If you are not sure whether you have the latest version or not of the EF then just use NuGet.

In my case the EF version is 5.0. Have a look at the picture below

 

4) We also need to add a reference to the System.Data.Entity namespace.Select References from the Solution Explorer and then choose Add Reference... You have to browse through the assemblies in the .Net Framework until you locate the System.Data.Entity and the click OK.

Have a look at the picture below

 

5)  Select the DAL folder, then right-click and then select Add -> New Item.We will add a class file, Poster.cs. Have a look at the picture below

 

6) Now we need to write the code for the Poster.cs Entity class.Please bear in mind that every instance of the Poster class (an object) will represent a row in the database table and every property in the class declaration will represent a table column. The code follows

public class Poster
    {
        [ScaffoldColumn(false)]
        public int PosterID { get; set; }

        [StringLength(50), Display(Name = "Poster Name")]
        public string PosterName { get; set; }

        [Required, StringLength(500), Display(Name = "Poster Description"), DataType(DataType.MultilineText)]
        public string PosterDescription { get; set; }

        public string PosterImgpath { get; set; }

        [Display(Name = "Price")]
        public double? PosterPrice { get; set; }

        
        public int? PosterCategoryID { get; set; }
   
    }

7) Select the DAL folder, then right-click and then select Add -> New Item.We will add a class file, PosterCategory.cs. The code follows

public class PosterCategory
    {
        [ScaffoldColumn(false)]
        public int PosterCategoryID { get; set; }

        [Required, StringLength(50), Display(Name = "Category Name")]
        public string PosterCategoryName { get; set; }

        [Required,StringLength(200),Display(Name = "Category Description")]
        public string CategoryDescription { get; set; }

        public List<Poster> Posters { get; set; }
    }

 

8) Select the DAL folder, then right-click and then select Add -> New Item.We will add another entity class called PosterContext.cs. This class will inherit from DbContext. Now that we have the entity classes created, we must let the model know.I will have to use the DbSet<T> property.

This class manages the domain classes and provides data access to the database.Think of it as an orchestrator class.

The code for this class follows

    public class PosterContext:DbContext
    {


        public DbSet<PosterCategory> PosterCategories { get; set; }
        public DbSet<Poster> Posters { get; set; }
    }

Do not forget to add  (using System.Data.Entity;) in the beginning of the class file.

I would like to talk at this point a little bit about Code First Data Annotations.With Data Annotations we can configure our domain-entity classes so that they can take best advantage of the EF.We will decorate our entity classes with declarative attributes.Let me give you an insight on how EF Code First works.EF Code First at run time, looks at the entity-domain classes and infers from them the in-memory data that it needs to interpret the queries and interact with the database.For example it assumes that any property named ID represents the key property of the class.Please have a look at this post of mine to find out more about Data Annotations.

9) Let's create a new class and add it in the DAL folder. I will call it PosterInsert.cs.In this class I will have the code to initialise the database and insert values.  The code for this class follows

     public class PosterInsert : DropCreateDatabaseIfModelChanges<PosterContext>
    {
        protected override void Seed(PosterContext context)
        {
            var pcategory = new List<PosterCategory>
            {
            new PosterCategory {
                
                PosterCategoryName = "Midfielders",CategoryDescription="Posters of active and past Liverpool Midfielders",
                Posters = new List<Poster>             
                {
                
                new Poster {PosterName = "King Kenny", PosterDescription="King Kenny lifting the European Cup",PosterImgpath="Images/posters/kenny-dalglish.jpg",PosterPrice=18.95},
                new Poster {PosterName = "John Barnes", PosterDescription="El mago-a true genius in the midfield",PosterImgpath="Images/posters/john-barnes.jpg",PosterPrice=16.95},
                new Poster {PosterName = "Steven Gerrard", PosterDescription="The Captain",PosterImgpath="Images/posters/steven-gerrard.jpg",PosterPrice=28.95},
 
                }
 
                            },
            
            new PosterCategory {
                
                PosterCategoryName = "Defenders",CategoryDescription="Posters of active and past Liverpool Defenders",
                Posters = new List<Poster>             
                {
                
                new Poster {PosterName = "Jamie Carragher", PosterDescription="Th greatest defender in the last ten years",PosterImgpath="Images/posters/jamie-carragher.jpg",PosterPrice=21.95},
                new Poster {PosterName = "Alan Hansen", PosterDescription="The legendary defender Alan Hansen",PosterImgpath="Images/posters/alan-hansen.jpg",PosterPrice=13.95},
                new Poster {PosterName = "Martin Skrtel", PosterDescription="The most promising defender playing right now",PosterImgpath="Images/posters/martin-skrtel.jpg",PosterPrice=19.95},
 
                }

            },


                            new PosterCategory {
                
                PosterCategoryName = "Strikers",CategoryDescription="Posters of active and past Liverpool Strikers",
                Posters = new List<Poster>             
                {
                
                new Poster {PosterName = "Ian Rush", PosterDescription="The greatest striker to wear a Liverpool shirt",PosterImgpath="Images/posters/ian-rush.jpg",PosterPrice=18.45},
                new Poster {PosterName = "Robbie Fowler", PosterDescription="Robbie, a goal scoring machine",PosterImgpath="Images/posters/robbie-fowler.jpg",PosterPrice=18.45},
                new Poster {PosterName = "Michael Owen", PosterDescription="The youngest deadliest striker Anfield has even known",PosterImgpath="Images/posters/michael-owen.jpg",PosterPrice=16.95},
 
                }
 
                            
       
        }
            };

            pcategory.ForEach(post => context.PosterCategories.Add(post));
                        base.Seed(context);
    }
}

In this class I inherit from the  DropCreateDatabaseIfModelChanges<PosterContext> class and I will override the default behaviour of that class with my class.

I will ovverride the Seed method with some data.Then I create 3 instances of the PosterCategory entity and 9 entities of the Poster entity.

Then through a simple lambda expression I add the data to the database using this last line of code,

base.Seed(context);

10)  Now we need to make one more change.in the Global.asax.cs.

In the Application_Start event handler routine (runs when the application starts) we will add this code

 Database.SetInitializer(new PosterInsert());

11) I have also created a Posters folder inside the Images folder and placed in it the 9 images.

12) Build and run your application. Everything should compile now. Have a look at the picture below to see the structure of the web application so far.

 

13) Now we will create a test page to see if the database is created and populated with values.Add a web form page to the application.Name it PostersTest.Add a gridview web server control on the page. Make the page as the Start Page

In the Page_Load event handling routine type

 

PosterContext ctx = new PosterContext();
 
    
var query = from postcat in ctx.PosterCategories select postcat.PosterCategoryName;

            GridView1.DataSource = query.ToList();
            GridView1.DataBind();

 

Build and run your application. Have a look below to see the result I have got.

 

It seems to work. The database is created and populated through the magic of EF Code First. Have a look at the web.config for the connection string. In the Solution Explorer look into the App_Data folder.

If you open the Server Explorer and open the connection to the database (in my case PostersOnLine.DAL.PosterContext.mdf).I am using LocalDB, which is anew version of SQL Express.For more information have a look here.

 

Have a look at the picture below.These are the results when I query the tables.

We can also have a look at the table's definitions.I select the PosterCategories table in the Server Explorer window and then choose "Open table definition".Have a look at the picture below.Please note that the table's definition is influenced by the data annotation attributes set in the domain classes.

 

I will do the same for the Posters table.In this case I also choose to show the T-SQL that is created for the table

Have a look at the picture below.EF Code First does a great job creating the database objects that reflect the definition and attributes in the domain classes.

 

Please make sure you follow all the steps.I will post soon part 3.

Hope it helps!!!!

1 Comment

Comments have been disabled for this content.