Click here to Skip to main content
15,868,096 members
Articles / Web Development / ASP.NET

ASP.NET MVC-3.0/ JqGrid/ Unit Of Work/ Repository/ EF 4.1 CRUD Application (N Layered)

Rate me:
Please Sign up or sign in to vote.
4.85/5 (14 votes)
23 Jan 2012CPOL4 min read 116.8K   119.9K   71   27
Design of multilayered web-based application operations using ASP.NET MVC 3.0/ JqGrid/ Unit of Work/ Repository/ EF 4.1 and a code demonstration of how to perform CRUD operations using it.

Introduction

In this article, I will demonstrate the design of multilayered web-based application operations using ASP.NET MVC 3.0/ JqGrid/ Unit of Work/ Repository/ EF 4.1 and later give code demonstration of how to perform CRUD operations using it.

I am assuming that you have basic understanding of ASP.NET MVC/JqGrid/Jquery and EF 4.1.

Design

  • DAL: Data Access Layer contains repositories, and EF 4.1 generated code, which handles interaction with underlying data store, and Entities.
  • BLL: Business Process Layer contains classes that incorporate application business rules. Furthermore, unit of work pattern is used in this layer to track all changes that can affect the database.
  • Web Application: It is an ASP.NET MVC based web application, through which users can interact with the application.

Design-Diagram.png

Project Structure

Project-Stucture.png

Implementation Details

EF 4.1 Database First Model

In the MVCJqGridCrud solution, add DAL, BLL and Web project.

Right click on DAL project, select add from the context menu and from the sub-menu, select New Item.

Select ADO.NET Entity Data Model.

Click Add.

NewEntityDataModelDialog.png

In follow up wizard, select generate from database.

Click Next.

EDMWizard-1.png

Note: I used database named as “ProgrammingEFDB1” for this demo which can be found in code folder (downloadable). It has two tables, contact and address.

The next step of the wizard will give you the options to configure your database connection.

Click on New Connection and select your desired database from connection property pop up. In this case, it is ProgrammingEFDB1.

Check the check box in bottom of the wizard which states “Save entity connection settings in App.Config as”.

EDMWizard-2.png

Click Next.

In the next step of the wizard, select only tables for this demo, and check the checkboxes at the bottom and click finish.

EDMWizard-3.png

Model1.edmx will be added in DAL project.

Double click on Model1.edmx to open the designer view of the file.

In the designer view, right click and from context menu select “Add code generation items”.

Select the ADO.NET DbContext Generator from the wizard to use simplified DbContext API.

There will be two items added to DAL project.

  • Model1.tt
    It contains POCO classes for each entity in your model.
  • Model1.Context.tt
    It derived from DBContext to use for querying and persisting data.

t4TemplateGeneration_small.png

Repository

A Repository mediates between the domain and data mapping layers, acting like an in-memory domain object collection. Repository isolates domain objects from details of the database access code.

I used specialized repositories, which derive from generic repository (base) with overridden or additional method. By this approach, I can benefit the use of common methods from generic repository and adding/overriding specialized method in specialized repository.

In this demo, I have kept possible common methods like GetById(), Add() in Base Repository. Meanwhile, a more specialized method named as GetContactsPaged() relevant to contact repository, is in Contact Repository.

RepositoryBase.cs (Generic Repository Class)

C#
public abstract class RepositoryBase<T> where T : class
    {
        internal ProgrammingEFDB1Entities _dataContext;
        internal DbSet<T> _dbset;
        public RepositoryBase(ProgrammingEFDB1Entities context)
        {
            this._dataContext = context;
            this._dbset = context.Set<T>();
        }
        public virtual List<T> Get(
            Expression<Func<T, bool>> filter = null,
            Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null,
            string includeProperties = "")
        {
            IQueryable<T> query = _dbset;

            if (filter != null)
            {
                query = query.Where(filter);
            }

            foreach (var includeProperty in includeProperties.Split
                (new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
            {
                query = query.Include(includeProperty);
            }

            if (orderBy != null)
            {
                return orderBy(query).ToList();
            }
            else
            {
                return query.ToList();
            }
        }

        public virtual void Add(T entity)
        {
            _dbset.Add(entity);
        }
        public virtual void Delete(T entity)
        {
            _dbset.Remove(entity);
        }
        public virtual void Delete(Expression<Func<T, bool>> where)
        {
            IEnumerable<T> objects = _dbset.Where<T>(where).AsEnumerable();
            foreach (T obj in objects)
                _dbset.Remove(obj);
        }
        public virtual T GetById(long id)
        {
            return _dbset.Find(id);
        }
        public virtual T GetById(string id)
        {
            return _dbset.Find(id);
        }
        public virtual IEnumerable<T> GetAll()
        {
            return _dbset.ToList();
        }
        public virtual IEnumerable<T> GetMany(Expression<Func<T, bool>> where)
        {
            return _dbset.Where(where).ToList();
        }
        public T Get(Expression<Func<T, bool>> where)
        {
            return _dbset.Where(where).FirstOrDefault<T>();
        }
    }

ContactRepository.cs

C#
public class ContactRepository : RepositoryBase<Contact>
    {
        public ContactRepository(ProgrammingEFDB1Entities context)
            : base(context)
        {

        }

        public List<Contact> GetContactPaged(int page, int rows, out int totalCount)
        {

            totalCount = _dataContext.Contacts.Count();
            return _dataContext.Contacts.OrderBy(c => c.ContactID).Skip
        (page * rows).Take(rows).ToList();
        }
    }

Unit of Work

A Unit of Work keeps track of everything you do during a business transaction that can affect the database. In my opinion, Unit of Work is somewhat similar to a transaction. It just encapsulates single business operation. In this demo, I make sure that each business operation has a new DBContext. When unitofwork.save() method is called, it will commit the changes in current DBContext.

UnitofWork.cs

C#
public class UnitOfWork : IDisposable
    {
        private ProgrammingEFDB1Entities _context;
        public UnitOfWork()
        {
            _context = new ProgrammingEFDB1Entities();
        }
        private ContactRepository _contactRepository;
        public ContactRepository ContactRepository
        {
            get
            {

                if (this._contactRepository == null)
                {
                    this._contactRepository = new ContactRepository(_context);
                }
                return _contactRepository;
            }
        }
        public void Save()
        {
            _context.SaveChanges();
        }

        private bool _disposed = false;

        protected virtual void Dispose(bool disposing)
        {
            if (!this._disposed)
            {
                if (disposing)
                {
                    _context.Dispose();
                }
            }
            this._disposed = true;
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
    }

Business Process Layer

It encapsulates the business logic of the application. In code demo, I have used only a single class in named as ManageContacts.cs for simplicity. It uses Unit of Work pattern for application business operations.

ManageContacts.cs

C#
public class ManageContacts
    {
        public IEnumerable<Contact> GetContacts()
        {
            IEnumerable<Contact> contacts;
            using (UnitOfWork unitOfWork = new UnitOfWork())
            {
                contacts = unitOfWork.ContactRepository.GetAll();
            }
            return contacts;
        }

        public bool AddContact(Contact contact)
        {
            using (UnitOfWork unitOfWork = new UnitOfWork())
            {
                unitOfWork.ContactRepository.Add(contact);
                unitOfWork.Save();
            }
            return true;
        }

        public bool UpdateContact(Contact contact, int id)
        {
            using (UnitOfWork unitOfWork = new UnitOfWork())
            {
                var contactEntity = unitOfWork.ContactRepository.GetById(id);
                contactEntity.Title = contact.Title;
                contactEntity.FirstName = contact.FirstName;
                contactEntity.LastName = contact.LastName;
                contactEntity.ModifiedDate = DateTime.Now;
                unitOfWork.Save();
            }
            return true;
        }

        public bool DeleteContact(int id)
        {
            using (UnitOfWork unitOfWork = new UnitOfWork())
            {
                Contact contact = unitOfWork.ContactRepository.GetById(id);
                unitOfWork.ContactRepository.Delete(contact);
                unitOfWork.Save();
            }
            return true;
        }

        public List<Contact> GetContactPaged(int page, int rows, out int totalCount)
        {
            List<Contact> contacts;
            using (UnitOfWork unitOfWork = new UnitOfWork())
            {
                contacts = unitOfWork.ContactRepository.GetContactPaged
                (page, rows, out totalCount);
            }
            return contacts;
        }
        public Contact GetById(int id)
        {
            Contact contact;
            using (UnitOfWork unitOfWork = new UnitOfWork())
            {
                contact = unitOfWork.ContactRepository.GetById(id);
            }
            return contact;
        }
    }

Controller

ASP.NET MVC controller coordinates between UI and model (data model).

Following action methods are added in our application.

  • GridDemoData(): It will return contacts data in json format to UI layer for JqGrid binding, handle user input for paging.
  • PerformCRUDOperation(): It handles CRUD inputs from user through JqGrid UI.

HomeController.cs

C#
public ActionResult GridDemoData(int page, int rows, 
    string search, string sidx, string sord)
        {
            var manageContacts = new ManageContacts();
            int currentPage = Convert.ToInt32(page) - 1;
            int totalRecords = 0;

            var data = manageContacts.GetContactPaged
        (currentPage, rows, out totalRecords);

            var totalPages = (int)Math.Ceiling(totalRecords / (float)rows);
            var jsonData = new
            {
                total = totalPages,
                page,
                records = totalRecords,

                rows = (
                           from m in data
                           select new
                           {
                               id = m.ContactID,
                               cell = new object[]
                                      {
                                           m.Title,
                                           m.FirstName,
                                           m.LastName
                                      }
                           }).ToArray()
            };
            return Json(jsonData, JsonRequestBehavior.AllowGet);
        }
        public ActionResult PerformCRUDAction(Contact contact)
        {
            var manageContacts = new ManageContacts();

            bool result = false;
            switch (Request.Form["oper"])
            {
                case "add":
                    contact.AddDate = DateTime.Now.Date;
                    contact.ModifiedDate = DateTime.Now;
                    result = manageContacts.AddContact(contact);
                    break;
                case "edit":
                    int id = Int32.Parse(Request.Form["id"]);
                    result = manageContacts.UpdateContact(contact,id);
                    break;
                case "del":
                    id = Int32.Parse(Request.Form["id"]);
                    result = manageContacts.DeleteContact(id);
                    break;
                default:
                    break;
            }
            return Json(result);
        }

View (UI Layer)

JqGrid Setup Requirements

The following code is used for JqGrid setup in site.master.

XML
<link href="<%= ResolveUrl("~/Content/themes/flick/ui.jqgrid.css") %>" rel="stylesheet"
        type="text/css" />

Following HTML code need to be added in index.aspx for JqGrid:

HTML
<div id="myDiv" style="width: 100%">
        <table id="grid" cellpadding="0" cellspacing="0">
        </table>
        <div id="pager" name="pager" style="text-align: center;">
        </div>

    </div>

Below is the JavaScript code for JqGrid in JqGridCRUD.js.

JavaScript
var lastsel;
$(function () {

    $("#grid").jqGrid({
        colNames: ['Title', 'First Name', 'Last Name'],
        colModel: [
                        { name: 'Title', index: 'Title', sortable: false, 
                align: 'left', width: '200',
                            editable: true, edittype: 'text'
                        },
                        { name: 'FirstName', index: 'FirstName', sortable: false, 
                align: 'left', width: '200',
                            editable: true, edittype: 'text'
                        },
                        { name: 'LastName', index: 'LastName', sortable: false, 
                align: 'left', width: '200',
                            editable: true, edittype: 'text'
                        }
                      ],
        pager: jQuery('#pager'),
        sortname: 'FirstName',
        rowNum: 10,
        rowList: [10, 20, 25],
        sortorder: "",
        height: 225,
        viewrecords: true,
        rownumbers: true,
        caption: 'Contacts',
        imgpath: '/Content/jqGridCss/smoothness/images',
        width: 750,
        url: "/Home/GridDemoData",
        editurl: "/Home/PerformCRUDAction",
        datatype: 'json',
        mtype: 'GET',
        onCellSelect: function (rowid, iCol, aData) {

            if (rowid && rowid !== lastsel) {

                if (lastsel)
                    jQuery('#grid').jqGrid('restoreRow', lastsel);
                jQuery('#grid').jqGrid('editRow', rowid, true);
                lastsel = rowid;
            }
        }
    })
    jQuery("#grid").jqGrid('navGrid', '#pager', 
    { edit: false, add: true, del: true, search: false, refresh: true },
            { closeOnEscape: true, reloadAfterSubmit: true, 
            closeAfterEdit: true, left: 400, top: 300 },
            { closeOnEscape: true, reloadAfterSubmit: true, 
            closeAfterAdd: true, left: 450, top: 300, width: 520 },
            { closeOnEscape: true, reloadAfterSubmit: true, left: 450, top: 300 });

});

UI Screen Shot

UI-ScreenShot_small.png

Conclusion

Find the code in the attached folder, and please don’t forget to rate or vote for this article. Furthermore, do add your comments to make it better.

History

  • 22nd January, 2012: Initial version

License

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


Written By
Software Developer (Senior) -
Pakistan Pakistan
i am working as a senior software developer.

aamirposwal.blogspot.com

Comments and Discussions

 
QuestionJqGrid Search Functionality Pin
Member 1046873226-Mar-14 19:58
professionalMember 1046873226-Mar-14 19:58 
Hi Aamir,
The Code you have given is working good. But I need implement Search functionality in my JqGrid, Can you please explain me how can i do this? Its very urgent, Please reply.
Thank you,
Ashish.
SuggestionGood But Not Working Pin
Sharath.Mitte24-Feb-14 3:10
professionalSharath.Mitte24-Feb-14 3:10 
QuestionHow to remove inline editing in your code? Pin
Member 1030892212-Feb-14 2:18
Member 1030892212-Feb-14 2:18 
QuestionI`m Can not Restore the database Pin
iamour26-Mar-13 15:58
iamour26-Mar-13 15:58 
QuestionEF Code First? Pin
negrito8028-Jan-13 12:21
negrito8028-Jan-13 12:21 
QuestionGetting Issues Pin
A Latif24-Nov-12 20:13
A Latif24-Nov-12 20:13 
AnswerRe: Getting Issues Pin
aamir sajjad24-Nov-12 22:22
aamir sajjad24-Nov-12 22:22 
GeneralRe: Getting Issues Pin
A Latif25-Nov-12 10:37
A Latif25-Nov-12 10:37 
QuestionHelp in implementing paging Pin
Member 321208014-Nov-12 19:30
Member 321208014-Nov-12 19:30 
GeneralMy vote of 5 Pin
maximan22-Oct-12 19:34
maximan22-Oct-12 19:34 
QuestionRepositories in UoW Pin
billym201011-Jun-12 11:43
billym201011-Jun-12 11:43 
QuestionHow to use method Get Pin
KratosBunbury15-May-12 7:05
KratosBunbury15-May-12 7:05 
GeneralSimilar architecture is in http://efmvc.codeplex.com/ Pin
Michael Freidgeim12-May-12 15:23
Michael Freidgeim12-May-12 15:23 
QuestionAbout "Unit Of Work" Pin
lGiles26-Apr-12 9:24
lGiles26-Apr-12 9:24 
Questionattaching the db Pin
spankbudda11-Apr-12 10:14
spankbudda11-Apr-12 10:14 
AnswerRe: attaching the db Pin
aamir sajjad11-Apr-12 14:43
aamir sajjad11-Apr-12 14:43 
GeneralRe: attaching the db Pin
Cyclone5529-Jun-12 16:10
Cyclone5529-Jun-12 16:10 
GeneralRe: attaching the db Pin
aamir sajjad29-Jun-12 19:14
aamir sajjad29-Jun-12 19:14 
GeneralMy vote of 5 Pin
rafimag20-Mar-12 2:44
rafimag20-Mar-12 2:44 
GeneralRe: My vote of 5 Pin
BJacks5-Apr-12 16:45
BJacks5-Apr-12 16:45 
GeneralMy vote of 5 Pin
Ashish Tripathi28-Feb-12 3:09
Ashish Tripathi28-Feb-12 3:09 
GeneralMy vote of 5 Pin
AlbertoLeon CSharpMan24-Jan-12 22:47
AlbertoLeon CSharpMan24-Jan-12 22:47 
Questionthis is different then yours. like its have different implementation technique of UoW, use of JqGrid etc. Pin
aamir sajjad24-Jan-12 7:05
aamir sajjad24-Jan-12 7:05 
AnswerRe: this is different then yours. like its have different implementation technique of UoW, use of JqGrid etc. Pin
Sacha Barber24-Jan-12 11:32
Sacha Barber24-Jan-12 11:32 
QuestionAmazing how many of these style articles there are this week Pin
Sacha Barber24-Jan-12 1:36
Sacha Barber24-Jan-12 1:36 

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

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