Sie sind auf Seite 1von 9

Repository and Unit of Work Patterns with

Entity Framework in ASP.NET MVC


Repository Pattern: A Repository is just a class of all kind of possible operations
that can be performed on an entity/object. May be the operations are CRUD (Create,
Retrieve, Update and Delete). Repository pattern based application is that where all
the entities are based on their respective repository class (generic/non-generic).
This kind of class can be non-generic in a sense that every entity will have a
separate class with the set of operations whereas it can be generic in a sense that
every entity will have a common class which is designed in a special way hence
offering a single access point of repository.
Repository Pattern consists of database entity models. Repository pattern ensures
SOC (Separation of Concern) in a sense that the application need not know about
the data source.
Following coding steps (1-5) can be realized to implement Repository and Unit of
Work Patterns with Entity Framework in ASP.NET MVC.
Step 1: Create an interface so that other generic repository class can implement it
and hence ensuring multiple inheritance
public interface IGenericRepository<TEntity>
{
IEnumerable<TEntity> Get();
TEntity GetByID(object id);
void Insert(TEntity entity);
void Delete(object id);
void Delete(TEntity entityToDelete);
void Update(TEntity entityToUpdate);
}

Step 2: Create a generic repository class for the entities so that it can be imagined
as if it was created for a single entity and hence reducing code duplicity
public class GenericRepository<TEntity> : IGenericRepository<TEntity> where TEntity : class
{
internal MvcAdvancedEntities context;
internal DbSet<TEntity> dbSet;
public GenericRepository(MvcAdvancedEntities context)
{
this.context = context;
this.dbSet = context.Set<TEntity>();
}
public virtual IEnumerable<TEntity> Get()
{

IQueryable<TEntity> query = dbSet;


return query.ToList();
}
public virtual TEntity GetByID(object id)
{
return dbSet.Find(id);
}
public virtual void Insert(TEntity entity)
{
dbSet.Add(entity);
}
public virtual void Delete(object id)
{
TEntity entityToDelete = dbSet.Find(id);
Delete(entityToDelete);
}
public virtual void Delete(TEntity entityToDelete)
{
if (context.Entry(entityToDelete).State == EntityState.Detached)
{
dbSet.Attach(entityToDelete);
}
dbSet.Remove(entityToDelete);
}
public virtual void Update(TEntity entityToUpdate)
{
dbSet.Attach(entityToUpdate);
context.Entry(entityToUpdate).State = EntityState.Modified;
}
}

Unit of Work Pattern: Unit of Work pattern is defined in a way that it is a single
transactional work for a set of operations including insert, update, delete etc. which
may encompass relational entities. Unit of Work comes along with the Repository
pattern to ensure keeping the database consistent.
Unit of Work pattern consists of Repositories and DBContext. Instead of having
the different DBContext instances for the respective repositories Unit of Work
pattern encompasses the same DBConext instance throughout the repositories.
This technique ensures that all the operations are committed successfully or none if
any one of them is failed in operations and this is how the database is carried out as
consistent as expected always.
Step 3: Create an interface so that other unit of work class can implement it and
hence ensuring multiple inheritance
public interface IUnitOfWork:IDisposable
{
IGenericRepository<Employee> EmployeeRepository{get;}

IGenericRepository<EmpRole> EmpRoleRepository{get;}
void Commit();
}

Step 4: Create a unit of work class so that operations can take place on the
entities as a single transactional work and hence ensuring database consistency
public class UnitOfWork : IUnitOfWork
{
private MvcAdvancedEntities context;
public UnitOfWork()
{
this.context = new MvcAdvancedEntities();
}
public UnitOfWork(MvcAdvancedEntities context)
{
this.context = context;
}
private IGenericRepository<Employee> employeeRepository;
private IGenericRepository<EmpRole> empRoleRepository;
public IGenericRepository<Employee> EmployeeRepository
{
get
{
if (this.employeeRepository == null)
this.employeeRepository = new GenericRepository<Employee>(context);
return employeeRepository;
}
}
public IGenericRepository<EmpRole> EmpRoleRepository
{
get
{
if (this.empRoleRepository == null)
this.empRoleRepository = new GenericRepository<EmpRole>(context);
return empRoleRepository;
}
}
public void Commit()
{
context.SaveChanges();
}
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (disposed)
return;
if (disposing)
{
//Free any other managed objects here.

context.Dispose();

// Free any unmanaged objects here.


disposed = true;

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

Controller: The ASP.NET MVC controller class is responsible for handling user input
and giving responses back to the user after getting output from the unit of work
abstraction layer.
Step 5: Create a controller class so that the controller can interact with the
database context through unit of work abstraction layer
public class EmployeeController : Controller
{
private UnitOfWork.UnitOfWork unitOfWork;
public EmployeeController()
{
unitOfWork = new UnitOfWork.UnitOfWork();
}
public EmployeeController(UnitOfWork.UnitOfWork unitOfWork)
{
this.unitOfWork = unitOfWork;
}
public ActionResult Index()
{
return View();
}
public IEnumerable<Employee> GetAllEmployees()
{
return (List<Employee>)unitOfWork.EmployeeRepository.Get();
}
public string Update(Employee employee)
{
if (employee != null)
{
var emp = unitOfWork.EmployeeRepository.GetByID(employee.ID);
emp.FirstName = employee.FirstName;
emp.LastName = employee.LastName;
emp.UserName = employee.UserName;
unitOfWork.EmployeeRepository.Update(emp);
unitOfWork.Commit();
return "Record has been Updated";

}
else
{
return "Record has not been Updated";
}

public string Delete(int id)


{
try
{
if (id != null)
{
unitOfWork.EmployeeRepository.Delete(id);
unitOfWork.Commit();
return "Employee has been Deleted";
}
else
{
return "Employee has not been Deleted";
}

}
catch
{
return "Employee has not been Deleted";
}

public string Add(Employee employee)


{
try
{
if (employee != null)
{
unitOfWork.EmployeeRepository.Insert(employee);
unitOfWork.Commit();
return "Record has been Added";
}
else
{
return "Record has not been Verified";
}
}

catch
{
return "Record has not been Added";
}

protected override void Dispose(bool disposing)


{
unitOfWork.Dispose();
base.Dispose(disposing);
}
}

The following figure shows one way to conceptualize the relationships between the
controller and context classes compared to not using the repository and unit of work
pattern at all.

Software design patterns are very important in the field of software engineering.
This is because design patterns give a software system scalability, testability,
reliability and maintainability. Design patterns are necessarily recurring solutions for
the recurring problems. A software engineer might have fall in difficulties while
finding some sort of viable solutions regarding a software system development. So,
if he/she picks a design pattern what is actually needed among the already invented
designed patterns then he/she would be able to save a lot of time by preventing
reinvention of the design pattern for the software system he/she is responsible for
to develop. Here, I would like to give some light on repository pattern and unit of
work pattern in a collective sense.

Handling Errors in MS SQL Server Stored Procedure


Here, I am going to cover the basics of Try-Catch error handling mechanism in T-SQL
which is introduced in SQL Server 2005. It includes the usage of error functions to
return information about the error using the Try-Catch block in stored procedures.
SQL Server uses the following basic syntax to capture errors in Transact-SQL
statements in just two steps in three different working scenarios:
WORKING WITH TRY-CATCH BLOCK AND ERROR FUNCTIONS
STEP 1:
BEGIN TRY
--Write necessary queries
END TRY
STEP 2:
BEGIN CATCH
SELECT
DECLARE @ErrorNumber INT = ERROR_NUMBER();
DECLARE @ErrorSeverity INT = ERROR_SEVERITY();
DECLARE @ErrorState INT = ERROR_STATE();
DECLARE @ErrorProcedure NVARCHAR(MAX) = ERROR_PROCEDURE();
DECLARE @ErrorLine INT = ERROR_LINE();
DECLARE @ErrorMessage NVARCHAR(MAX) = ERROR_MESSAGE();
PRINT
PRINT
PRINT
PRINT
PRINT
PRINT

'Actual
'Actual
'Actual
'Actual
'Actual
'Actual

error
error
error
error
error
error

number: ' + CAST(@ErrorNumber AS VARCHAR(10));


severity: ' + CAST(@ErrorSeverity AS VARCHAR(10));
state: ' + CAST(@ErrorState AS VARCHAR(10));
procedure: ' + @ErrorProcedure;
line: ' + CAST(@ErrorLine AS VARCHAR(10));
message: ' + @ErrorMessage;

END CATCH

In the scope of the Catch block the error functions return error-related information
that you can reference in your T-SQL statements. Currently, SQL Server supports the
following functions for this purpose:

ERROR_NUMBER(): The number assigned to the error.


ERROR_LINE(): The line number inside the routine that caused the error.
ERROR_MESSAGE(): The error message text.

ERROR_SEVERITY(): The error severity.


ERROR_STATE(): The error state number.
ERROR_PROCEDURE(): The name of the stored procedure or trigger that
generated the error.

WORKING WITH TRY-CATCH BLOCK, ERROR FUNCTIONS AND @@TRANCOUNT BUILT IN FUNCTION

@@TRANCOUNT function is used to determine whether any transactions are still


open. If there is a situation where the numbers of the opened transactions are at
least one (in case of an error occurs) then roll back transaction can take place.
STEP 1:
BEGIN TRY
--Write necessary queries with transactions
END TRY
STEP 2:
BEGIN CATCH
IF @@TRANCOUNT > 0
ROLLBACK TRANSACTION
SELECT
DECLARE
DECLARE
DECLARE
DECLARE
DECLARE
DECLARE
PRINT
PRINT
PRINT
PRINT
PRINT
PRINT

@ErrorNumber INT = ERROR_NUMBER();


@ErrorSeverity INT = ERROR_SEVERITY();
@ErrorState INT = ERROR_STATE();
@ErrorProcedure NVARCHAR(MAX) = ERROR_PROCEDURE();
@ErrorLine INT = ERROR_LINE();
@ErrorMessage NVARCHAR(MAX) = ERROR_MESSAGE();

'Actual
'Actual
'Actual
'Actual
'Actual
'Actual

error
error
error
error
error
error

number: ' + CAST(@ErrorNumber AS VARCHAR(10));


severity: ' + CAST(@ErrorSeverity AS VARCHAR(10));
state: ' + CAST(@ErrorState AS VARCHAR(10));
procedure: ' + @ErrorProcedure;
line: ' + CAST(@ErrorLine AS VARCHAR(10));
message: ' + @ErrorMessage;

END CATCH
WORKING WITH TRY-CATCH BLOCK AND THROW STATEMENT INSTEAED OF ERROR FUNCTIONS

To simplify returning errors in a Catch block, SQL Server 2012 introduced


the Throw statement. With the Throw statement, we dont have to specify any
parameters and the results are more accurate. You should simply include the
statement as it is shown in the Catch block.

STEP 1:
BEGIN TRY
--Write necessary queries with/without transactions
END TRY
STEP 2:
BEGIN CATCH
IF @@TRANCOUNT > 0
ROLLBACK TRANSACTION
THROW
END CATCH