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

CRUD Operations Using the Generic Repository Pattern and Unit of Work in MVC

, 15 Sep 2014
Rate this:
Please Sign up or sign in to vote.
This article introduces the Generic Repository pattern and Unit of Work in ASP.NET MVC applications.

Introduction

This article introduces the Generic Repository pattern and Unit of Work in ASP.NET MVC applications. We are developing an application for a Book entity on which we can do Create, Read, Update and Delete operations. To keep the article simple and to make it easy to understand, the Generic Repository pattern and Unit of Work, we use a single book entity in the application.

In the previous article, “CRUD Operations Using the Repository Pattern in MVC", we created a book repository for a book entity and it's good for one entity that does CRUD operations but suppose we have an enterprise level application and that application has more than one entity, we need to create a repository for each entity. In short, we can say that we are repeating the code for each entity's repository against DRY (every piece of knowledge must have a single, unambiguous, authoritative representation within a system) principle in the software engineering; that's why we need a generic repository pattern. As in Figure 1.1, two developers have a question “Whether to create a new part or to reuse an existing one.” One developer chooses the option to create a new one as discussed in the article CRUD Operations Using the Repository Pattern in MVC but another developer chooses the second option, to reuse an existing code so that you can reduce code. So now you are the second developer and your approach is Generic Repository Pattern and Unit of Work and it's also the main goal of this article as well.

Reuse and Reduce code question

Figure 1.1 Reuse and Reduce (Courtesy: http://perspectives.3ds.com/)

Our Roadmap towards Learning MVC with Entity Framework

The Repository Pattern

The Repository pattern is intended to create an abstraction layer between the data access layer and the business logic layer of an application. It is a data access pattern that prompts a more loosely coupled approach to data access. We create the data access logic in a separate class, or set of classes, called a repository, with the responsibility of persisting the application's business model.

In this article, we design a common generic repository for all entities and a Unit of work class. The Unit of Work class creates a repository instance for each entity and the repository is used to do CURD operations. We create an instance of the UnitOfWork class in the controller, then create a repository instance depending on the entity and thereafter use the methods of the repository as per the operations.

The following diagram shows the relationship between the repository and the Entity Framework data context, in which MVC controllers interact with the repository by a Unit of Work rather than directly with the Entity Framework.

Generic Repository Pattern and Unit of Work workflow

Figure 1.2 Generic Repository Pattern and Unit of Work workflow

Why Unit of Work

A Unit of Work, as its name applies, does something. In this article, a Unit of Work does whatever we create an instance of it then it instantiates our DbContext thereafter each repository instance uses the same DbContext for database operations. So the Unit of Work is the pattern that ensures that all repositories use the same database context.

Implement a Generic Repository and a Unit of Work Class

Note: In this article, your user interface uses a concrete class object, not an interface because that concept I will describe in the next article. To keep this short code and only describe the concepts, I removed error handling code from the controller but you should always use error handling in your controller.

In this section of articles, we create two projects, one is EF.Core and another is EF.Data. In this article, we are working with Entity Framework Code First Approach so the project EF.Core contains entities that are needed in the application's database. In this EF.Data project, we create two entities, one is the BaseEntity class that has common properties that will be inherited by each entity and the other is Book. Let's see each entity. The following is a code snippet for the BaseEntity class.

using System;
namespace EF.Core
{
   public abstract class BaseEntity
    {
        public Int64 ID { get; set; }
        public DateTime AddedDate { get; set; }
        public DateTime ModifiedDate { get; set; }
        public string IP { get; set; }
    }
}

Now, we create a Book entity under the Data folder of the EF.Core project which inherits from the BaseEntity class. The following is a code snippet for the Book entity.

using System;

namespace EF.Core.Data
{
   public class Book : BaseEntity
    {
       public string Title { get; set; }
       public string Author { get; set; }
       public string ISBN { get; set; }
       public DateTime Published { get; set; }
    }
} 

The EF.Data project contains DataContext, Book entity Mapping, Repository and Unit of Work classes. The ADO.NET Entity Framework Code First data access approach requires us to create a data access context class that inherits from the DbContext class so we create a context class EFDbContext (EFDbContext.cs) class. In this class, we override the OnModelCreating() method. This method is called when the model for a context class (EFDbContext) has been initialized, but before the model has been locked down and used to initialize the context such that the model can be further configured before it is locked down. The following is the code snippet for the context class.

using System;
using System.Data.Entity;
using System.Data.Entity.ModelConfiguration;
using System.Linq;
using System.Reflection;
using EF.Core;

namespace EF.Data
{
   public class EFDbContext : DbContext
    {
       public EFDbContext()
           : base("name=DbConnectionString")
       {
       }

       public new IDbSet<TEntity> Set<TEntity>() where TEntity : BaseEntity
       {
           return base.Set<TEntity>();
       }

       protected override void OnModelCreating(DbModelBuilder modelBuilder)
       {
           var typesToRegister = Assembly.GetExecutingAssembly().GetTypes()
          .Where(type => !String.IsNullOrEmpty(type.Namespace))
          .Where(type => type.BaseType != null && type.BaseType.IsGenericType
               && type.BaseType.GetGenericTypeDefinition() == typeof(EntityTypeConfiguration<>));
           foreach (var type in typesToRegister)
           {
               dynamic configurationInstance = Activator.CreateInstance(type);
               modelBuilder.Configurations.Add(configurationInstance);
           }
           base.OnModelCreating(modelBuilder);
       }
    }
} 

As you know, the EF Code First approach follows convention over configuration, so in the constructor, we just pass the connection string name, the same as an App.Config file and it connects to that server. In the OnModelCreating() method, we used reflection to map an entity to its configuration class in this specific project.

Project structure in solution

Figure 1.3 Project structure in solution

Now, we define the configuration for the book entity that will be used when the database table will be created by the entity. The configuration defines the class library project EF.Data under the Mapping folder. Now create configuration classes for the entity. For the Book entity, we create the BookMap entity.

The following is a code snippet for the BookMap class.

using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.ModelConfiguration;
using EF.Core.Data;

namespace EF.Data.Mapping
{
   public class  BookMap : EntityTypeConfiguration<Book>
    {
       public BookMap()
       {
           HasKey(t => t.ID);
           Property(t => t.ID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
           Property(t => t.Title).IsRequired();
           Property(t => t.Author).IsRequired();
           Property(t => t.ISBN).IsRequired();
           Property(t => t.Published).IsRequired();
           ToTable("Books");
       }
    }
}

Now, we create a generic repository class. We are not creating an interface for a repository so that our article will be easy to understand. This generic repository has all CRUD operation methods. This repository contains a parameterized constructor with a parameter as Context so when we create an instance of the repository, we pass a context so that all the repositories for each entity has the same context. We are using the saveChanges() method of the context but you can also use the save method of the Unit of Work class because both have the same context. The following is a code snippet for the Generic Repository.

using System;
using System.Data.Entity;
using System.Data.Entity.Validation;
using System.Linq;
using EF.Core;

namespace EF.Data
{
   public class Repository<T> where T : BaseEntity
    {
        private readonly EFDbContext context;
        private IDbSet<t> entities;
        string errorMessage = string.Empty;

        public Repository(EFDbContext context)
        {
            this.context = context;
        }

        public T GetById(object id)
        {
            return this.Entities.Find(id);
        }

        public void Insert(T entity)
        {
            try
            {
                if (entity == null)
                {
                    throw new ArgumentNullException("entity");
                }
                this.Entities.Add(entity);
                this.context.SaveChanges();
            }
            catch (DbEntityValidationException dbEx)
            {

                foreach (var validationErrors in dbEx.EntityValidationErrors)
                {
                    foreach (var validationError in validationErrors.ValidationErrors)
                    {
                        errorMessage += string.Format("Property: {0} Error: {1}",
                        validationError.PropertyName, validationError.ErrorMessage) + Environment.NewLine;
                    }
                }
                throw new Exception(errorMessage, dbEx);
            }
        }

        public void Update(T entity)
        {
            try
            {
                if (entity == null)
                {
                    throw new ArgumentNullException("entity");
                }
                this.context.SaveChanges();
            }
            catch (DbEntityValidationException dbEx)
            {
                foreach (var validationErrors in dbEx.EntityValidationErrors)
                {
                    foreach (var validationError in validationErrors.ValidationErrors)
                    {
                        errorMessage += Environment.NewLine + string.Format("Property: {0} Error: {1}",
                        validationError.PropertyName, validationError.ErrorMessage);
                    }
                }

                throw new Exception(errorMessage, dbEx);
            }
        }

        public void Delete(T entity)
        {
            try
            {
                if (entity == null)
                {
                    throw new ArgumentNullException("entity");
                }

                this.Entities.Remove(entity);
                this.context.SaveChanges();
            }
            catch (DbEntityValidationException dbEx)
            {

                foreach (var validationErrors in dbEx.EntityValidationErrors)
                {
                    foreach (var validationError in validationErrors.ValidationErrors)
                    {
                        errorMessage += Environment.NewLine + string.Format("Property: {0} Error: {1}",
                        validationError.PropertyName, validationError.ErrorMessage);
                    }
                }
                throw new Exception(errorMessage, dbEx);
            }
        }

        public virtual IQueryable<t> Table
        {
            get
            {
                return this.Entities;
            }
        }

        private IDbSet<t> Entities
        {
            get
            {
                if (entities == null)
                {
                    entities = context.Set<t>();
                }
                return entities;
            }
        }
    }
}  

Now to create a class for the Unit of Work; that class is UnitOfWork. This class inherits from an IDisposable interface so that its instance will be disposed of in each controller. This class initiates the application DataContext. This class heart is the Repository() method that returns a repository for the entity and that entity inherits from the BaseEntity class. The following is a code snippet for the UnitOfWork class.

using System;
using System.Collections.Generic;
using EF.Core;

namespace EF.Data
{
   public class UnitOfWork : IDisposable
    {
       private readonly EFDbContext context;
       private bool disposed;
       private Dictionary<string,object> repositories;

       public UnitOfWork(EFDbContext context)
       {
           this.context = context;
       }

       public UnitOfWork()
       {
           context = new EFDbContext();
       }

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

       public void Save()
       {
           context.SaveChanges();
       }

       public virtual void Dispose(bool disposing)
       {
           if (!disposed)
           {
               if (disposing)
               {
                   context.Dispose();
               }
           }
           disposed = true;
       }

       public Repository<T> Repository<t>() where T : BaseEntity
       {
           if (repositories == null)
           {
               repositories = new Dictionary<string,object>();
           }

           var type = typeof(T).Name;

           if (!repositories.ContainsKey(type))
           {
               var repositoryType = typeof(Repository<>);
               var repositoryInstance = Activator.CreateInstance(repositoryType.MakeGenericType(typeof(T)), context);
               repositories.Add(type, repositoryInstance);
           }
           return (Repository<t>)repositories[type];
       }
    }
} 

An MVC Application Using the Generic Repository Pattern

Now, we create an MVC application (EF.Web) as in Figure 1.3. This is our third project of the application, this project contains user interface for a Book entity's CRUD operations and the controller to do these operations. First, we proceed to the controller. Create a BookController under the Controllers folder of the application. This controller has all ActionResult methods for each user interface of a CRUD operation. We first create a Unit of Work class instance then the controller's constructor initiates the repository as per the required entity. The following is a code snippet for the BookController.

using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using EF.Core.Data;
using EF.Data;

namespace EF.Web.Controllers
{
    public class BookController : Controller
    {
        private UnitOfWork unitOfWork = new UnitOfWork();
        private Repository<book> bookRepository;

        public BookController()
        {
            bookRepository = unitOfWork.Repository<book>();
        }

        public ActionResult Index()
        {
            IEnumerable<book> books = bookRepository.Table.ToList();
            return View(books);
        }

        public ActionResult CreateEditBook(int? id)
        {
            Book model = new Book();
            if (id.HasValue)
            {
                model = bookRepository.GetById(id.Value);
            }
            return View(model);
        }

        [HttpPost]
        public ActionResult CreateEditBook(Book model)
        {
            if (model.ID == 0)
            {
                model.ModifiedDate = System.DateTime.Now;
                model.AddedDate = System.DateTime.Now;
                model.IP = Request.UserHostAddress;
                bookRepository.Insert(model);
            }
            else
            {
                var editModel = bookRepository.GetById(model.ID);
                editModel.Title = model.Title;
                editModel.Author = model.Author;
                editModel.ISBN = model.ISBN;
                editModel.Published = model.Published;
                editModel.ModifiedDate = System.DateTime.Now;
                editModel.IP = Request.UserHostAddress;
                bookRepository.Update(editModel);
            }

            if (model.ID > 0)
            {
                return RedirectToAction("Index");
            }
            return View(model);
        }

        public ActionResult DeleteBook(int id)
        {
            Book model = bookRepository.GetById(id);
            return View(model);
        }

        [HttpPost,ActionName("DeleteBook")]
        public ActionResult ConfirmDeleteBook(int id)
        {
            Book model = bookRepository.GetById(id);
            bookRepository.Delete(model);
            return RedirectToAction("Index");
        }

        public ActionResult DetailBook(int id)
        {
            Book model = bookRepository.GetById(id);
            return View(model);
        }

        protected override void Dispose(bool disposing)
        {
            unitOfWork.Dispose();
            base.Dispose(disposing);
        }
    }
}

We have now developed the BookController to handle CURD operation request for a book entity. Now to develop the user interface for the CRUD operations. We develop it for the views for adding and editing a book, a book listing, book delete and book details. Let's see each one by one.

Create / Edit Book View

We create a common view for creating and editing a book such as CreateEditBook.cshtml under the Book folder of the views. We use a date picker to choose the date for the book published date. That is why we write JavaScript code for date picker.

(function ($) {
    function Book() {
        var $thisthis = this;
        function initializeAddEditBook() {
            $('.datepicker').datepicker({
                "setDate": new Date(),
                "autoclose": true
            });
        }
        $this.init = function () {
            initializeAddEditBook();
        }
    }
    $(function () {
        var self = new Book();
        self.init();
    });
}(jQuery)) 

Now define a create/edit book view and the following is a code snippet for CreateEditBook.cshtml.

@model EF.Core.Data.Book

@{
    ViewBag.Title = "Create Edit Book";
}
<div class="book-example panel panel-primary">
    <div class="panel-heading panel-head">Add / Edit Book</div>
    <div class="panel-body">
        @using (Html.BeginForm())
        {
            <div class="form-horizontal">
                <div class="form-group">
                    @Html.LabelFor(model => model.Title,
                    new { @class = "col-lg-1 control-label" })
                    <div class="col-lg-9">
                        @Html.TextBoxFor(model => model.Title,
                        new { @class = "form-control" })
                    </div>
                </div>
                <div class="form-group">
                    @Html.LabelFor(model => model.ISBN,
                    new { @class = "col-lg-1 control-label" })
                    <div class="col-lg-9">
                        @Html.TextBoxFor(model => model.ISBN,
                        new { @class = "form-control" })
                    </div>
                </div>
                <div class="form-group">
                    @Html.LabelFor(model => model.Author,
                    new { @class = "col-lg-1 control-label" })
                    <div class="col-lg-9">
                        @Html.TextBoxFor(model => model.Author,
                        new { @class = "form-control" })
                    </div>
                </div>
                <div class="form-group">
                    @Html.LabelFor(model => model.Published,
                    new { @class = "col-lg-1 control-label" })
                    <div class="col-lg-9">
                        @Html.TextBoxFor(model => model.Published,
                        new { @class = "form-control datepicker" })
                    </div>
                </div>
                <div class="form-group">
                    <div class="col-lg-8"></div>
                    <div class="col-lg-3">
                        @Html.ActionLink("Back to List", "Index",
                        null, new { @class = "btn btn-default" })
                        <button class="btn btn-success"
                        id="btnSubmit" type="submit">
                            Submit
                        </button>
                    </div>
                </div>
            </div>
        }
    </div>
</div>
@section scripts
{
    <script src="~/Scripts/bootstrap-datepicker.js" type="text/javascript"></script>
    <script src="~/Scripts/book-create-edit.js" type="text/javascript"></script>
} 

Now run the application and call the CreateEditBook() action method with a HttpGet request, then we get the UI as in Figure 1.4 to add a new book to the application.

Add new book UI

Figure 1.4 : Add new book UI

Book List View

This is the first view when the application is accessed or the entry point of the application is executed. It shows the book listing as in Figure 1.5. We display book data in tabular format and on this view, we create links to add a new book, edit a book, delete a book and the details of a book. This view is an index view and the following is a code snippet for index.cshtml under the Book folder of View.

@model IEnumerable<EF.Core.Data.Book>
@using EF.Web.Models

<div class="book-example panel panel-primary">
    <div class="panel-heading panel-head">Books Listing</div>
    <div class="panel-body">
        <a id="createEditBookModal"
        href="@Url.Action("CreateEditBook")" class="btn btn-success">
            <span class="glyphicon glyphicon-plus"></span>Book
        </a>

        <table class="table" style="margin: 4px">
            <tr>
                <th>
                    @Html.DisplayNameFor(model => model.Title)
                </th>
                <th>
                    @Html.DisplayNameFor(model => model.Author)
                </th>
                <th>
                    @Html.DisplayNameFor(model => model.ISBN)
                </th>
                <th>Action
                </th>

                <th></th>
            </tr>
            @foreach (var item in Model)
            {
                <tr>
                    <td>
                        @Html.DisplayFor(modelItem => item.Title)
                    </td>
                    <td>
                        @Html.DisplayFor(modelItem => item.Author)
                    </td>
                    <td>
                        @Html.DisplayFor(modelItem => item.ISBN)
                    </td>
                    <td>
                        @Html.ActionLink("Edit", "CreateEditBook",
                        new { id = item.ID }, new { @class = "btn btn-success" }) |
                        @Html.ActionLink("Details", "DetailBook",
                        new { id = item.ID }, new { @class = "btn btn-primary" }) |
                        @Html.ActionLink("Delete", "DeleteBook",
                        new { id = item.ID }, new { @class = "btn btn-danger" })
                    </td>
                </tr>
            }

        </table>
    </div>
</div> 

When we run the application and call the index() action with an HttpGet request, then we get all the books listed in the UI as in Figure 1.5. This UI has options for CRUD operations.

Books Listing UI

Figure 1.5 Books Listing UI.

As in the figure above, each book has an option for Edit; when we click on the Edit button then the CreateEditBook() action method is called with an HttpGet request and the UI is shown as in Figure 1.6.

 Edit a book UI

Figure 1.6 Edit a book UI.

Now, we change input field data and click on the submit button, then the CreateEditBook() action method is called with a HttpPost request and that book data is successfully updated in the database.

Book Detail View

We create a view that shows specific book details when the details button is clicked in the book listing data. We call the DetailBook() action method with a HttpGet request that shows a “Details” view such as in Figure 1.7 so we create a view DetailBook and the following is a code snippet for DetailBook.cshtml.

 @model EF.Core.Data.Book
@{
    ViewBag.Title = "Detail Book";
}
<div class="book-example panel panel-primary">
    <div class="panel-heading panel-head">Book Detail</div>
    <div class="panel-body">
        <div class="form-horizontal">
            <div class="form-group">
                @Html.LabelFor(model => model.Title, new { @class = "col-lg-1 control-label" })
                <div class="col-lg-9">
                    @Html.DisplayFor(model => model.Title, new { @class = "form-control" })
                </div>
            </div>

            <div class="form-group">
                @Html.LabelFor(model => model.Author, new { @class = "col-lg-1 control-label" })
                <div class="col-lg-9">
                    @Html.DisplayFor(model => model.Author, new { @class = "form-control" })
                </div>
            </div>

            <div class="form-group">
                @Html.LabelFor(model => model.ISBN, new { @class = "col-lg-1 control-label" })
                <div class="col-lg-9">
                    @Html.DisplayFor(model => model.ISBN, new { @class = "form-control" })
                </div>
            </div>

            <div class="form-group">
                @Html.LabelFor(model => model.Published, new { @class = "col-lg-1 control-label" })
                <div class="col-lg-9">
                    @Html.DisplayFor(model => model.Published, new { @class = "form-control" })
                </div>
            </div>

            <div class="form-group">
                @Html.LabelFor(model => model.AddedDate, new { @class = "col-lg-1 control-label" })
                <div class="col-lg-9">
                    @Html.DisplayFor(model => model.AddedDate, new { @class = "form-control" })
                </div>
            </div>

            <div class="form-group">
                @Html.LabelFor(model => model.ModifiedDate, new { @class = "col-lg-1 control-label" })
                <div class="col-lg-9">
                    @Html.DisplayFor(model => model.ModifiedDate, new { @class = "form-control" })
                </div>
            </div>

            <div class="form-group">
                @Html.LabelFor(model => model.IP, new { @class = "col-lg-1 control-label" })
                <div class="col-lg-9">
                    @Html.DisplayFor(model => model.IP, new { @class = "form-control" })
                </div>
            </div>

            @using (Html.BeginForm())
            {
                <div class="form-group">
                    <div class="col-lg-1"></div>
                    <div class="col-lg-9">
                        @Html.ActionLink("Edit", "CreateEditBook",
                        new { id = Model.ID }, new { @class = "btn btn-primary" })
                        @Html.ActionLink("Back to List", "Index",
                        null, new { @class = "btn btn-success" })
                    </div>
                </div>
            }
        </div>
    </div>
</div>   

Book Detail UI

Figure 1.7 Book Detail UI

Delete Book

Delete a book is the last operation of this article. To delete a book, we follow the process of clicking on the Delete button that exists in the Book listing data then the book detail view shows to ask “You are sure you want to delete this?” after clicking on the Delete button that exists in the Delete view such as in Figure 1.8. When we click the Delete button of the book list, then it makes an HttpGet request that calls the DeleteBook() action method that shows a delete view, then clicks on the Delete button of the view, then an HttpPost request makes that call to ConfirmDeleteBook() action methods that delete that book.

The following is a code snippet for DeleteBook.cshtml.

@model EF.Core.Data.Book

@{
    ViewBag.Title = "Delete Book";
}

<div class="book-example panel panel-primary">
    <div class="panel-heading panel-head">Delete Book</div>
    <div class="panel-body">
        <h3>Are you sure you want to delete this?</h3>
        <h1>@ViewBag.ErrorMessage</h1>
        <div class="form-horizontal">
            <div class="form-group">
                @Html.LabelFor(model => model.Title,
                new { @class = "col-lg-1 control-label" })
                <div class="col-lg-9">
                    @Html.DisplayFor(model => model.Title,
                    new { @class = "form-control" })
                </div>
            </div>

            <div class="form-group">
                @Html.LabelFor(model => model.Author,
                new { @class = "col-lg-1 control-label" })
                <div class="col-lg-9">
                    @Html.DisplayFor(model => model.Author,
                    new { @class = "form-control" })
                </div>
            </div>

            <div class="form-group">
                @Html.LabelFor(model => model.ISBN,
                new { @class = "col-lg-1 control-label" })
                <div class="col-lg-9">
                    @Html.DisplayFor(model => model.ISBN,
                    new { @class = "form-control" })
                </div>
            </div>

            <div class="form-group">
                @Html.LabelFor(model => model.Published,
                new { @class = "col-lg-1 control-label" })
                <div class="col-lg-9">
                    @Html.DisplayFor(model => model.Published,
                    new { @class = "form-control" })
                </div>
            </div>

            <div class="form-group">
                @Html.LabelFor(model => model.AddedDate,
                new { @class = "col-lg-1 control-label" })
                <div class="col-lg-9">
                    @Html.DisplayFor(model => model.AddedDate,
                    new { @class = "form-control" })
                </div>
            </div>

            <div class="form-group">
                @Html.LabelFor(model => model.ModifiedDate,
                new { @class = "col-lg-1 control-label" })
                <div class="col-lg-9">
                    @Html.DisplayFor(model => model.ModifiedDate,
                    new { @class = "form-control" })
                </div>
            </div>

            <div class="form-group">
                @Html.LabelFor(model => model.IP,
                new { @class = "col-lg-1 control-label" })
                <div class="col-lg-9">
                    @Html.DisplayFor(model => model.IP,
                    new { @class = "form-control" })
                </div>
            </div>

            @using (Html.BeginForm())
            {
                <div class="form-group">
                    <div class="col-lg-1"></div>
                    <div class="col-lg-9">
                        <input type="submit" value="Delete"
                        class="btn btn-danger" />
                        @Html.ActionLink("Back to List", "Index",
                        null, new { @class = "btn btn-success" })
                    </div>
                </div>
            }
        </div>
    </div>
</div>  

Delete a Book View

Figure 1.8 Delete a Book View.

Conclusion

This article introduced the generic repository pattern with unit of work. I used bootstrap CSS and JavaScript for the user interface design in this application. What do you think about this article? Please provide your feedback.

License

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

Share

About the Author

Sandeep Singh Shekhawat
Software Developer Dotsquares Technology Pvt Ltd, Jaipur
India India

Comments and Discussions

 
GeneralPlease stop posting this rubbish. Pinmemberstevenbey19-Sep-14 6:52 
GeneralMy vote of 5 PinmemberMahsa Hassankashi17-Sep-14 3:17 
GeneralVote PinmemberShemeemsha RA16-Sep-14 0:34 
GeneralRe: Vote PinprofessionalSandeep Singh Shekhawat16-Sep-14 18:06 
QuestionNice Article PinmemberJúnior Pacheco11-Sep-14 15:30 
AnswerRe: Nice Article PinprofessionalSandeep Singh Shekhawat11-Sep-14 16:02 
GeneralMy vote of 1 Pinmemberady cody10-Sep-14 0:27 
QuestionGeneric Repository is not a good idea PinmemberJalpesh Vadgama8-Sep-14 1:45 
AnswerRe: Generic Repository is not a good idea PinprofessionalSandeep Singh Shekhawat8-Sep-14 4:27 
GeneralNice one... PinmemberKundan Singh Chouhan5-Sep-14 7:23 
GeneralRe: Nice one... PinprofessionalSandeep Singh Shekhawat5-Sep-14 16:01 
GeneralSome suggestions PinmemberStephen Zeng4-Sep-14 20:07 
GeneralRe: Some suggestions PinprofessionalSandeep Singh Shekhawat5-Sep-14 16:05 
SuggestionUnit of Work Pinmemberbuckrogerz4-Sep-14 11:34 
GeneralRe: Unit of Work PinprofessionalSandeep Singh Shekhawat4-Sep-14 16:07 
QuestionMy vote of 4 PinmemberNathan Minier4-Sep-14 3:34 
AnswerRe: My vote of 4 PinprofessionalSandeep Singh Shekhawat4-Sep-14 6:32 
GeneralRe: My vote of 4 PinmemberNathan Minier4-Sep-14 6:42 
GeneralRe: My vote of 4 PinprofessionalSandeep Singh Shekhawat4-Sep-14 7:04 
GeneralExcellent article - voted 5 Pinmemberscott.leckie4-Sep-14 3:02 
GeneralRe: Excellent article - voted 5 PinprofessionalSandeep Singh Shekhawat4-Sep-14 6:34 
GeneralMy vote of 5 PinmemberHumayun Kabir Mamun3-Sep-14 21:08 
GeneralRe: My vote of 5 PinprofessionalSandeep Singh Shekhawat4-Sep-14 6:33 
GeneralMy vote of 5 PinmemberHalil ibrahim Kalkan3-Sep-14 6:43 
GeneralRe: My vote of 5 PinprofessionalSandeep Singh Shekhawat3-Sep-14 7:16 
GeneralRe: My vote of 5 PinmemberHalil ibrahim Kalkan3-Sep-14 7:21 
GeneralRe: My vote of 5 PinprofessionalSandeep Singh Shekhawat3-Sep-14 16:18 

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
Web03 | 2.8.140921.1 | Last Updated 15 Sep 2014
Article Copyright 2014 by Sandeep Singh Shekhawat
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid