Sunday, January 31, 2016

ASP.NET MVC web application : SCRUD web application using Entity Framework, JQuery and Ajax


Introduction

SCRUD mean Search, Create, Read, Update and Delete, those basic operations may be useful for every application that include a DataBase.

In This article we will explain :

- SCRUD process by using Entity Framework (EF) first method,
In the end our web application will look like the image below :



Background

This article may be useful for intermediate developers who have some basics in HTML, Ajax, JQuery, JavaScript, Entity Framework, C# and ASP.NET MVC.

Using the code

In what follows, we will explain the different functionalities of the application, respecting the MVC pattern.
To have a reminder about MVC pattern, you can visit the following link : Dynamic Content Load, using jQuery AJAX.

I) Model :

  • Create local DataBase :

to create your local DataBase (.mdf), you can follow the same instructions showen in Dynamic Content Load, using jQuery AJAX.
  • Sql instructions :

I want to create a Product record that contain those informations :
  • Product Name
  • Product Description
  • Product Image
to meet this need, i created a table in database titled 'Product' through SQL instructions. You can use the integrated SGBD tools to create your table manually :

create table Product( P_id int identity(1,1) Primary key, P_name varchar(50) default '', P_description varchar(300) default '', P_image_path varchar(300) default '') ;
  • P_id : is the unique identifier of our product, and have an auto-icrement integer value,
  • P_name : is the product name, string type,
  • P_description : takes some details of product, string type,
  • P_image_path : only take the name of saved image in servers side.
Note : To find image path, we must know about the container folder full path. so the full path of image will be composed by  :

full_container_path + P_image_path.

example in c# : 
string full_image_path =  Server.MapPath("~/Content/images/") + "image.jpg" ;
  • Using Entity Framework (First method approch) :

To use this ORM, you can follow the same steps as indicated in Dynamic Content Load, using jQuery AJAX.

II) Controller :

In this section we will talk about the different services that implements the SCRUD operations.
For each service, we will present its signature and its implementation.
  • Search and Reading products :

the logic adopted in this service is :

a) Arguments :

FilterName : filter name,

b) Body :

If the filter name has null value , all datas will be loaded, else the returned products are those whose names beginning with FilterName.

c) Result :

HTML dataset that contains the list of available products.

d) Implementation : C# Code

 public string Select()  
    {  
      StringBuilder dataHTML = new StringBuilder();  
      try  
      {  
        //get the filter  
        string FilterName = Request.Params["IdFilterName"];  
        //Entity Framework  
        var list = dataBaseContext.Product.ToList();  
        if(FilterName !="" && FilterName != null){  
          //to change the process of filter : you can replace statWith by another condition for example equals.  
          list = list.Where(x => x.P_name.StartsWith(FilterName, StringComparison.InvariantCultureIgnoreCase)).ToList();  
        }  
        //fetch All product list  
        foreach (var product in list)  
         { //For each product create a html block  
           dataHTML.Append("<div class='row'>");  
           dataHTML.Append("<div class='col-xs-3'>");  
           if (product.P_image_path != null && product.P_image_path != "")  
           {  
            dataHTML.Append(string.Format("<img class='img-responsive' src='/Content/images/{0}'>", product.P_image_path));  
           }  
           else  
           {  
             dataHTML.Append("<img class='img-responsive' src='http://placehold.it/100x70'>");  
           }  
           dataHTML.Append("</div>");  
           dataHTML.Append("<div class='col-xs-7'>");  
           dataHTML.Append(string.Format("<input type='hidden' value='{0}'><h4 class='product-name'><strong>{1}</strong></h4><h4><small>{2}</small></h4>", product.P_id, product.P_name, product.P_description));  
           dataHTML.Append("</div>");  
           dataHTML.Append("<div class='col-xs-2'>");  
           dataHTML.Append("<a href='#' id='idModifyProduct'><span class='glyphicon glyphicon-pencil'></span></a> ");  
           dataHTML.Append("<a href='#' id='idDeleteProduct'><span class='glyphicon glyphicon-trash'></span></a></div></div><hr>");  
         }  
      }  
      catch (Exception e)  
      {  
        ;  
      }  
      return dataHTML.ToString();  
    }  
  • Insertion Product :

the logic adopted in this service is :

a) Arguments :

ProductName : text data, that contains the name of product,
ProductDescription : text data, that contains details of product,
imageFile : submited image file, that contains the binary data.

b) Body :
creating of new product data, based on submited values, and add it to our product table.

c) Result :
return statu as string value, if 'true' means that the update process has successfully done, else an exception was revealed .

d) Implementation : C# code


 public string AddProduct()  
     {  
       string statu = "true";  
       try{  
         var ProductName = Request.Params["idProductName"];  
         var ProductDescription = Request.Params["idProductDescription"];  
         HttpPostedFileBase imageFile = Request.Files["idImage"];  
         //we create new instance of product  
         WebApplication1.Models.Product product = new Models.Product();  
         product.P_name = ProductName;  
         product.P_description = ProductDescription;  
         //to avoid redundancy in image path  
         string imageServerPath = "";  
         //save new picture  
         if(imageFile!=null && imageFile.ContentLength>0)  
         {  
           imageServerPath = Server.MapPath("~/Content/images/");  
           imageServerPath = System.IO.Path.Combine(imageServerPath, System.IO.Path.GetRandomFileName().Replace('.',' ')+System.IO.Path.GetExtension(imageFile.FileName));  
           imageFile.SaveAs(imageServerPath);  
         }  
         product.P_image_path = System.IO.Path.GetFileName(imageServerPath);  
         //add our new product  
         dataBaseContext.Product.Add(product);  
         //save changes  
         dataBaseContext.SaveChanges();  
       }catch(Exception e){  
         statu = "false";  
       }  
       return statu;  
     }  
  • Updating Product :

the logic adopted in this service is :

a) Arguments :

productKey : integer data, that contains the product identifier,
ProductName : text data, that contains the name of product,
ProductDescription : text data, that contains details of product,
imageFile : submited image file, that contains the binary data.

b) Body :

fetch a product record, whose identifier is equal to productKey.
Once find it, its properties will be replaced by new ones.

c) Result :

return statu as string value, if 'true' means that the insertion process has successfully done, else an exception was revealed .

d) Implementation : C# code

 public string ModifyProdut()  
     {  
       string statu = "true";  
       try  
       {  
         //get unique key of product  
         var productKey = int.Parse(Request.Params["ProductKey"]);  
         //build our delete query  
         var ProductName = Request.Params["idProductName"];  
         var ProductDescription = Request.Params["idProductDescription"];  
         HttpPostedFileBase imageFile = Request.Files["idImage"];  
         //update product object  
         WebApplication1.Models.Product product = dataBaseContext.Product.Where(x => x.P_id == productKey).First();  
         product.P_name = ProductName;  
         product.P_description = ProductDescription;  
         //to avoid redundancy in image path  
         string imageServerPath = "";  
         //remove old picture if exists  
         if (product.P_image_path!="")  
         {  
           try  
           {  
             //delete old file  
             System.IO.File.Delete(product.P_image_path);  
           }  
           catch (Exception e)  
           {  
             ;  
           }  
         }  
         //save new picture  
         if(imageFile!=null && imageFile.ContentLength>0)  
         {  
           imageServerPath = Server.MapPath("~/Content/images/");  
           imageServerPath = System.IO.Path.Combine(imageServerPath, System.IO.Path.GetRandomFileName().Replace('.', ' ') + System.IO.Path.GetExtension(imageFile.FileName));  
           imageFile.SaveAs(imageServerPath);  
         }  
         product.P_image_path = System.IO.Path.GetFileName(imageServerPath);  
         //save changes   
         dataBaseContext.SaveChanges();  
       }  
       catch (Exception e)  
       {  
         statu = "false";  
       }  
       return statu;  
     }  

  • Deleting  Product :

the logic adopted in this service is

a) Arguments :
productKey : integer data, that contains the product identifier,
b) Body :
fetch a product record, whose identifier is equal to productKey.
Once find it, it will be deleted.
c) Result :
return statu as string value, if 'true' means that the deleting process has successfully done, else an exception was revealed .

d) Implementation : C# code

 public string DeleteProduct()  
     {  
       string statu = "true";  
       //get unique key of product  
       try{  
         var productKey = int.Parse(Request.Params["ProductKey"]);  
         //perform query : remove product form database  
         var employer = new WebApplication1.Models.Product { P_id = productKey };  
         dataBaseContext.Product.Attach(employer);  
         dataBaseContext.Product.Remove(employer);  
         dataBaseContext.SaveChanges();  
       }catch(Exception e){  
         statu = "false";  
       }  
       return statu;  
     }  

III) VIEW (User interface) :

Before, you start coding you must need to include jquery library :
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
  • JavaScript Code :

- LoadAllData :  this method call Search and Reading products service.

function LoadAllData(name) { //specify a url of service; var url = "/Home/Select"; //display all data; //ajax request $.post(url, { 'IdFilterName': name }, function (dataHTML) { $("#outputData").html(dataHTML); }); }
- Form Filter : when user clic on filter button after writing text, this action will be raised and will invokes LoadAllData method

 $("#formFilter").submit(function (e) {  
       e.preventDefault();  
       //take the name of produt from input text  
       var nameProduct = $("#IdFilterName").val();  
       //load Filtered Data  
       LoadAllData(nameProduct);  
     });  

Addition and Modification action :

this action will be invoked after form submitted,
first it will choose the adequate url of service, initialize form data and sumbit will submit a ajax request to :

- if action type = Modication  action : the insertion service will be called.
- if action type = Insertion action :  the updating service will be called.

 $("#AddModifForm").submit(function (e) {  
       e.preventDefault();  
       //initialisation  
       //initialize url variable to target on Modification or Creation service;  
       var url = "/Home/AddProduct/";  
       if ($("#idDivProductID").is(":visible")) {  
         url = "/Home/ModifyProdut/"  
       }  
       //get all data;  
       var formdata = (window.FormData) ? new FormData(this) : null;  
       var fdata = (formdata !== null) ? formdata : $form.serialize();  
       //send ajax request  
       $.ajax({  
         url: url,  
         data: fdata,  
         processData: false,  
         contentType: false,  
         type: 'POST',  
         success: function (resp) {  
           if (resp == "true") {  
             alert("change is done");  
             LoadAllData("");  
           } else {  
             alert("unsuccessful change !");  
           }  
         }  
       });  
     });  

 
Clic on modification button action :

This method is called when user click on edit button of a product row.
The main functionality is to bind current selected product with form fields.

 //Modification product action implementation  
     $(document).on("click", "#idModifyProduct", function () {  
       //initialisation  
       //get all data;  
       var Parent = $($($(this).parent()).parent()).children()[1];  
       var ProductKey = $($(Parent).children()[0]).val();  
       var ProductName = $($($(Parent).children()[1]).children()[0]).text();  
       var ProductDescription = $($($(Parent).children()[2]).children()[0]).text();  
       // binding data with the formular  
       $("#idDivProductID").show();  
       $("#ProductKey").val(ProductKey);  
       $("#idProductName").val(ProductName);  
       $("#idProductDescription").val(ProductDescription);  
       //The following code : change add icon to chevron-up icon  
       if (!$("#AddModifForm").is(":visible")) {  
         $("#AddModifForm").slideToggle("slow");  
         $('#toggle1').toggleClass(function () {  
           if ($("#AddModifForm").is(":visible"))  
             return '.fa fa-chevron-up';  
         });  
       }  
     });  

Clic on deleting button action :

This method is called when user click on delete button of a product row.
The main functionality is to call Deleting Product  service.

  //Delete product action implementation  
 $(document).on("click", "#idDeleteProduct", function () {  
   //initialisation  
   var Parent = $($($(this).parent()).parent()).children()[1];  
   //get product Name  
   var ProductName = $($($(Parent).children()[1]).children()[0]).text();  
   var result = confirm("Are you sure, you want to delete "+ ProductName +" ?");  
   if (result == true) {  
     //user confirm deleting by clicking on OK button  
     //specify a url of service  
     var url = "/Home/DeleteProduct/";  
     //get Product KEY  
     var ProductKey = $($(Parent).children()[0]).val();  
     //send ajax request to delete prduct  
     $.post(url, { 'ProductKey': ProductKey }, function (resp) {  
       if (resp == "true") {  
         alert("change is done");  
         //refresh data  
         LoadAllData("");  
       } else {  
         alert("unsuccessful change!");  
       }  
     });  
   } else {  
    //the delete operation was canceled  
   }  
 });  

  • HTML code :


 <div class="col-xs-10">  
     <div class="panel panel-info">  
       <div class="panel-heading">  
         <div class="navbar-form navbar-light bg-faded" role="search">  
           <div class="row">  
             <form id="formFilter" class="navbar-form navbar-left" role="search">  
               <div class="input-group">  
                 <input type="text" id="IdFilterName" class="form-control" placeholder="Filter By Product Name">  
                 <span class="input-group-btn">  
                   <button class="btn btn-default" type="submit"> Validate</button>  
                 </span>  
               </div>  
             </form>  
             <div class="form-group navbar-form pull-right">  
               <a href="#" id="toggle1" class="fa fa-plus-circle fa-1x" data-toggle="tooltip" data-placement="right" title="Add Product"><i></i></a>  
             </div>  
           </div>  
         </div>  
       </div>  
       <div class="panel-body">  
         <div class="row">  
           <form id="AddModifForm" class="form-horizontal">  
             <div id="idDivProductID" class="form-group">  
               <label class="col-sm-2 control-label">Product ID</label>  
               <div class="col-sm-10">  
                 <input type="text" class="form-control" id="ProductKey" name="ProductKey" readonly>  
               </div>  
             </div>  
             <div class="form-group">  
               <label class="col-sm-2 control-label">Name</label>  
               <div class="col-sm-10">  
                 <input type="text" class="form-control" id="idProductName" name="idProductName" placeholder="Product Name">  
               </div>  
             </div>  
             <div class="form-group">  
               <label class="col-sm-2 control-label">Description</label>  
               <div class="col-sm-10">  
                 <textarea class="form-control" id="idProductDescription" name="idProductDescription" placeholder=" Product description"></textarea>  
               </div>  
             </div>  
             <div class="form-group">  
               <div class="col-sm-10 col-sm-offset-2">  
                 <input type="file" id="idImage" name="idImage">  
               </div>  
             </div>  
             <div class="form-group">  
               <div class="col-sm-offset-2 col-sm-10">  
                 <button type="submit" class="btn btn-default">save</button>  
               </div>  
             </div>  
           </form>  
         </div>  
         <hr>  
         <div id="outputData">  
         </div>  
       </div>  
     </div>  
   </div>  

IV) User interface manipulation :

For each action, we will show you some scenario
  • Insertion a new product :
Intial state,

 
 
When user clic on add button ,the form will appear,

 
 
User must complete the form and validate,

 
 
If the insertion is well done, the new product will be added to the HTML view.

  • Display all product : 
  • Search product by name : 
User write some text into Filter and validate,

 
 
if the search is not empty, the list of product will be updated into the HTML view.

  • Updating an existing product :
When user click on edit button , the product detail will be binding into form,

 
 
User can modify product details, and clic on save button,

 
 
If the update is successfully done, the HTML view will be updated.


  • Deleting product :
When user click on delete button , the alert box will appear, if User confirm the deletion by clicking on OK button, the selected product will disappear.


Points of Interest

The main aim of this article, is to learn how we can doing SCRUD operation using Entity Framework through an Asp.net MVC web application.

I hope that you appreciated my effort. Thank you for viewing my blog post, try to download the source code and do not hesitate to leave your questions and comments.

History

- v2 : Updates Search and Reading products service code by using StringBuilder class instead of string.

No comments:

Post a Comment