Implementing Repository Pattern With Entity Framework






4.77/5 (54 votes)
Implement Repository Pattern in data access layer with Entity Framework 4.0 and below version (working with ObjectContext and EntityObject )
Introduction
The Repository pattern is defined by Patterns of Enterprise Application Architecture as:
Mediates between the domain and data mapping layers using a collection-like interface for accessing domain objects.
Repository provides an in-memory like collection interface for accessing domain objects. So as far as the consuming component is concerned, it uses the repository just like a collection when working with Domain objects. The repository then neatly abstracts the internal mechanics of how the Add / Remove calls to the repository translate to the actual data access calls to the data store. Objects can be added to and removed from the Repository, as they can from a simple collection of objects, and the mapping code encapsulated by the Repository will carry out the appropriate operations behind the scenes. Conceptually, a Repository encapsulates the set of objects persisted in a data store and the operations performed over them, providing a more object-oriented view of the persistence layer. Repository also supports the objective of achieving a clean separation and one-way dependency between the domain and data mapping layers.
So with the repository, we get a nice abstraction that provides us with persistence ignorance and a nice separation of concerns where the responsibility of persisting domain objects is encapsulated by the Repository leaving the domain objects to deal entirely with the domain model and domain logic. Here are some reasons for using repository pattern in data access layer in place direct access the database code:
- Duplicated code
- A higher potential for programming errors
- Weak typing of the business data
- Difficulty in centralizing data-related policies such as caching
- An inability to easily test the business logic in isolation from external dependencies
Using the Code
Here, I use the Composite Repository pattern:
/// <summary>
/// Repository Interface defines the base
/// functionality required by all Repositories.
/// </summary>
/// <typeparam name="T">
/// The entity type that requires a Repository.
/// </typeparam>
public interface IRepository<E>
{
string KeyProperty { get; set; }
void Add(E entity);
void AddOrAttach(E entity);
void DeleteRelatedEntries(E entity);
void DeleteRelatedEntries
(E entity, ObservableCollection<string> keyListOfIgnoreEntites);
void Delete(E entity);
ObjectQuery<E> DoQuery();
ObjectQuery<E> DoQuery(ISpecification<E> where);
ObjectQuery<E> DoQuery(int maximumRows, int startRowIndex);
ObjectQuery<E> DoQuery(Expression<Func<E, object>> sortExpression);
ObjectQuery<E> DoQuery(Expression<Func<E, object>> sortExpression,
int maximumRows, int startRowIndex);
IList<E> SelectAll(string entitySetName);
IList<E> SelectAll();
IList<E> SelectAll(string entitySetName, ISpecification<E> where);
IList<E> SelectAll(ISpecification<E> where);
IList<E> SelectAll(int maximumRows, int startRowIndex);
IList<E> SelectAll(Expression<Func<E, object>> sortExpression);
IList<E> SelectAll(Expression<Func<E, object>> sortExpression,
int maximumRows, int startRowIndex);
E SelectByKey(string Key);
bool TrySameValueExist(string fieldName, object fieldValue, string key);
bool TryEntity(ISpecification<E> selectSpec);
int GetCount();
int GetCount(ISpecification<E> selectSpec);
}
You can write your own Repository
for each business object like RoleRepository
, UserReporsitory
, etc. Or you can implement this interface
as a generic class of Repository
something like this:
public class Repository<E, C> : IRepository<E>
where E : class
where C : ObjectContext
{
private readonly C _ctx;
private string _KeyProperty = "ID";
public string KeyProperty
{
get
{
return _KeyProperty;
}
set
{
_KeyProperty = value;
}
}
public C Session
{
get { return _ctx; }
}
public Repository(C session)
{
_ctx = session;
}
#region IRepository<E,C> Members
public int Save()
{
return _ctx.SaveChanges();
}
/// <summary>
/// A generic method to return ALL the entities
/// </summary>
/// <param name=”entitySetName”>
/// The EntitySet name of the entity in the model.
/// </param>
/// <typeparam name=”TEntity”>
/// The Entity to load from the database.
/// </typeparam>
/// <returns>Returns a set of TEntity.</returns>
private ObjectQuery<E> DoQuery(string entitySetName)
{
return _ctx.CreateQuery<E>("[" + entitySetName + "]");
}
/// <summary>
/// A generic method to return ALL the entities
/// </summary>
/// <typeparam name=”TEntity”>
/// The Entity to load from the database.
/// </typeparam>
/// <returns>Returns a set of TEntity.</returns>
public ObjectQuery<E> DoQuery()
{
return _ctx.CreateQuery<E>("[" + this.GetEntitySetName( typeof(E).Name) + "]");
}
/// <summary>
/// </summary>
/// <param name=”entitySetName”>
/// The EntitySet name of the entity in the model.
/// </param>
/// <typeparam name=”TEntity”>
/// The Entity to load from the database.
/// </typeparam>
/// <returns>Returns a set of TEntity.</returns>
private ObjectQuery<E> DoQuery(string entitySetName, ISpecification<E> where)
{
return
(ObjectQuery<E>)_ctx.CreateQuery<E>("[" + entitySetName + "]")
.Where(where.EvalPredicate);
}
/// <summary>
/// </summary>
/// <typeparam name=”TEntity”>
/// The Entity to load from the database.
/// </typeparam>
/// <returns>Returns a set of TEntity.</returns>
public ObjectQuery<E> DoQuery(ISpecification<E> where)
{
return
(ObjectQuery<E>)_ctx.CreateQuery<E>
("[" + this.GetEntitySetName( typeof(E).Name ) + "]")
.Where(where.EvalPredicate);
}
/// <summary>
/// Query Entity with Paging
/// </summary>
/// <param name="maximumRows">Max no of row to Fetch</param>
/// <param name="startRowIndex">Start Index</param>
/// <returns>Collection of Entities</returns>
public ObjectQuery<E> DoQuery(int maximumRows, int startRowIndex)
{
return (ObjectQuery<E>)_ctx.CreateQuery<E>
("[" + this.GetEntitySetName(typeof(E).Name) + "]").Skip<E>
(startRowIndex).Take(maximumRows);
}
/// <summary>
/// Query Entity in sorted Order
/// </summary>
/// <param name="sortExpression">Sort Expression/condition</param>
/// <param name="ErrorCode">custom Error Message</param>
/// <returns>Collection of Entities</returns>
public ObjectQuery<E> DoQuery(Expression<Func<E, object>> sortExpression)
{
if (null == sortExpression)
{
return this.DoQuery();
}
return (ObjectQuery<E>)((IRepository<E>)this).DoQuery().OrderBy
<E, object>(sortExpression);
}
/// <summary>
/// Query All Entity in sorted Order with Paging support
/// </summary>
/// <param name="sortExpression">Sort Expression/condition</param>
/// <param name="maximumRows">Max no of row to Fetch</param>
/// <param name="startRowIndex">Start Index</param>
/// <returns>Collection Of entities</returns>
public ObjectQuery<E> DoQuery(Expression<Func<E, object>>
sortExpression, int maximumRows, int startRowIndex)
{
if (sortExpression == null)
{
return ((IRepository<E>)this).DoQuery(maximumRows, startRowIndex);
}
return (ObjectQuery<E>)((IRepository<E>)this).DoQuery
(sortExpression).Skip<E>(startRowIndex).Take(maximumRows);
}
/// <summary>
/// A generic method to return ALL the entities
/// </summary>
/// <param name=”entitySetName”>
/// The EntitySet name of the entity in the model.
/// </param>
/// <typeparam name=”TEntity”>
/// The Entity to load from the database.
/// </typeparam>
/// <returns>Returns a set of TEntity.</returns>
public IList<E> SelectAll(string entitySetName)
{
return DoQuery(entitySetName).ToList();
}
/// <summary>
/// A generic method to return ALL the entities
/// </summary>
/// <typeparam name=”TEntity”>
/// The Entity to load from the database.
/// </typeparam>
/// <returns>Returns a set of TEntity.</returns>
public IList<E> SelectAll()
{
try
{
return DoQuery().ToList(); //_ctx.CreateQuery<E>("[" + typeof(E).Name + "]");
}
catch (Exception)
{
throw;
}
}
/// <summary>
/// A generic method to return ALL the entities
/// </summary>
/// <param name=”entitySetName”>
/// The EntitySet name of the entity in the model.
/// </param>
/// <typeparam name=”TEntity”>
/// The Entity to load from the database.
/// </typeparam>
/// <returns>Returns a set of TEntity.</returns>
public IList<E> SelectAll(string entitySetName, ISpecification<E> where)
{
return DoQuery(entitySetName, where).ToList();
}
/// <summary>
/// A generic method to return ALL the entities
/// </summary>
/// <typeparam name=”TEntity”>
/// The Entity to load from the database.
/// </typeparam>
/// <returns>Returns a set of TEntity.</returns>
public IList<E> SelectAll(ISpecification<E> where)
{
return DoQuery(where).ToList();
}
/// <summary>
/// Select All Entity with Paging
/// </summary>
/// <param name="maximumRows">Max no of row to Fetch</param>
/// <param name="startRowIndex">Start Index</param>
/// <returns>Collection of Entities</returns>
public IList<E> SelectAll(int maximumRows, int startRowIndex)
{
return DoQuery(maximumRows, startRowIndex).ToList();
}
/// <summary>
/// Select All Entity in sorted Order
/// </summary>
/// <param name="sortExpression">Sort Expression/condition</param>
/// <param name="ErrorCode">custom Error Message</param>
/// <returns>Collection of Entities</returns>
public IList<E> SelectAll(Expression<Func<E, object>> sortExpression)
{
if (null == sortExpression)
{
return DoQuery(sortExpression).ToList();
}
return DoQuery(sortExpression).ToList();
}
/// <summary>
/// Select All Entity in sorted Order with Paging support
/// </summary>
/// <param name="sortExpression">Sort Expression/condition</param>
/// <param name="maximumRows">Max no of row to Fetch</param>
/// <param name="startRowIndex">Start Index</param>
/// <returns>Collection Of entities</returns>
public IList<E> SelectAll(Expression<Func<E, object>>
sortExpression, int maximumRows, int startRowIndex)
{
if (sortExpression == null)
{
return DoQuery(maximumRows, startRowIndex).ToList();
}
return DoQuery(sortExpression, maximumRows, startRowIndex).ToList();
}
/// <summary>
/// Get Entity By Primary Key
/// </summary>
/// <typeparam name="E">Entity Type</typeparam>
/// <param name="Key">Primary Key Value</param>
/// <returns>return entity</returns>
public E SelectByKey(string Key)
{
// First we define the parameter that we are going to use the clause.
var xParam = Expression.Parameter(typeof(E), typeof(E).Name);
MemberExpression leftExpr = MemberExpression.Property(xParam, this._KeyProperty);
Expression rightExpr = Expression.Constant(Key);
BinaryExpression binaryExpr = MemberExpression.Equal(leftExpr, rightExpr);
//Create Lambda Expression for the selection
Expression<Func<E, bool>> lambdaExpr =
Expression.Lambda<Func<E, bool>>(binaryExpr,
new ParameterExpression[] { xParam });
//Searching ....
var resultCollection = (ObjectQuery<E>)_ctx.CreateQuery<E>
("[" + this.GetEntitySetName(typeof(E).Name) + "]")
.Where(lambdaExpr);
if (null != resultCollection && resultCollection.Count() > 0)
{
//return valid single result
return resultCollection.First<E>();
}//end if
return null;
}
/// <summary>
/// Check if value of specific field is already exist
/// </summary>
/// <typeparam name="E"></typeparam>
/// <param name="fieldName">name of the Field</param>
/// <param name="fieldValue">Field value</param>
/// <param name="key">Primary key value</param>
/// <returns>True or False</returns>
public bool TrySameValueExist(string fieldName, object fieldValue, string key)
{
// First we define the parameter that we are going to use the clause.
var xParam = Expression.Parameter(typeof(E), typeof(E).Name);
MemberExpression leftExprFieldCheck =
MemberExpression.Property(xParam, fieldName);
Expression rightExprFieldCheck = Expression.Constant(fieldValue);
BinaryExpression binaryExprFieldCheck =
MemberExpression.Equal(leftExprFieldCheck, rightExprFieldCheck);
MemberExpression leftExprKeyCheck =
MemberExpression.Property(xParam, this._KeyProperty);
Expression rightExprKeyCheck = Expression.Constant(key);
BinaryExpression binaryExprKeyCheck =
MemberExpression.NotEqual(leftExprKeyCheck, rightExprKeyCheck);
BinaryExpression finalBinaryExpr =
Expression.And(binaryExprFieldCheck, binaryExprKeyCheck);
//Create Lambda Expression for the selection
Expression<Func<E, bool>> lambdaExpr =
Expression.Lambda<Func<E, bool>>(finalBinaryExpr,
new ParameterExpression[] { xParam });
//Searching ....
return _ctx.CreateQuery<E>
("[" + this.GetEntitySetName(typeof(E).Name) + "]").Any<E>
(lambdaExpr);
}
/// <summary>
/// Check if Entities exist with Condition
/// </summary>
/// <param name="selectExpression">Selection Condition</param>
/// <returns>True or False</returns>
public bool TryEntity(ISpecification<E> selectSpec)
{
return _ctx.CreateQuery<E>("[" +
this.GetEntitySetName( typeof(E).Name ) + "]").Any<E>
(selectSpec.EvalPredicate);
}
/// <summary>
/// Get Count of all records
/// </summary>
/// <typeparam name="E"></typeparam>
/// <returns>count of all records</returns>
public int GetCount()
{
return _ctx.CreateQuery<E>("[" +
this.GetEntitySetName( typeof(E).Name ) + "]").Count();
}
/// <summary>
/// Get count of selection
/// </summary>
/// <typeparam name="E">Selection Condition</typeparam>
/// <returns>count of selection</returns>
public int GetCount(ISpecification<E> selectSpec)
{
return _ctx.CreateQuery<E>("[" + this.GetEntitySetName( typeof(E).Name ) + "]")
.Where(selectSpec.EvalPredicate).Count();
}
/// <summary>
/// Delete data from context
/// </summary>
/// <typeparam name="E"></typeparam>
/// <param name="entity"></param>
public void Delete(E entity)
{
_ctx.DeleteObject(entity);
}
/// <summary>
/// Delete data from context
/// </summary>
/// <typeparam name="E"></typeparam>
/// <param name="entity"></param>
public void Delete(object entity)
{
_ctx.DeleteObject(entity);
}
/// <summary>
/// Insert new data into context
/// </summary>
/// <typeparam name="E"></typeparam>
/// <param name="entity"></param>
public void Add(E entity)
{
_ctx.AddObject( this.GetEntitySetName(entity.GetType().Name), entity);
}
/// <summary>
/// Insert if new otherwise attach data into context
/// </summary>
/// <param name="entity"></param>
public void AddOrAttach(E entity)
{
// Define an ObjectStateEntry and EntityKey for the current object.
EntityKey key;
object originalItem;
// Get the detached object's entity key.
if (((IEntityWithKey)entity).EntityKey == null)
{
// Get the entity key of the updated object.
key = _ctx.CreateEntityKey
(this.GetEntitySetName(entity.GetType().Name), entity);
}
else
{
key = ((IEntityWithKey)entity).EntityKey;
}
try
{
// Get the original item based on the entity key from the context
// or from the database.
if (_ctx.TryGetObjectByKey(key, out originalItem))
{//accept the changed property
if (originalItem is EntityObject &&
((EntityObject)originalItem).EntityState != EntityState.Added)
{
// Call the ApplyCurrentValues method to apply changes
// from the updated item to the original version.
_ctx.ApplyCurrentValues(key.EntitySetName, entity);
}
}
else
{//add the new entity
Add(entity);
}//end else
}
catch (Exception ex)
{
throw ex;
}
}
/// <summary>
/// Delete all related entries
/// </summary>
/// <param name="entity"></param>
public void DeleteRelatedEntries(E entity)
{
foreach (var relatedEntity in (((IEntityWithRelationships)entity).
RelationshipManager.GetAllRelatedEnds().SelectMany(re =>
re.CreateSourceQuery().OfType<EntityObject>()).Distinct()).ToArray())
{
_ctx.DeleteObject(relatedEntity);
}//end foreach
}
/// <summary>
/// Delete all related entries
/// </summary>
/// <param name="entity"></param>
public void DeleteRelatedEntries(E entity, ObservableCollection<string>
keyListOfIgnoreEntites)
{
foreach (var relatedEntity in (((IEntityWithRelationships)entity).
RelationshipManager.GetAllRelatedEnds().SelectMany(re =>
re.CreateSourceQuery().OfType<EntityObject>()).Distinct()).ToArray())
{
PropertyInfo propInfo = relatedEntity.GetType().GetProperty
(this._KeyProperty);
if (null != propInfo)
{
string value = (string)propInfo.GetValue(relatedEntity, null);
if (!string.IsNullOrEmpty(value) &&
keyListOfIgnoreEntites.Contains(value))
{
continue;
}//end if
}//end if
_ctx.DeleteObject(relatedEntity);
}//end foreach
}
private string GetEntitySetName(string entityTypeName)
{
var container = this._ctx.MetadataWorkspace.GetEntityContainer
(this._ctx.DefaultContainerName, DataSpace.CSpace);
return (from meta in container.BaseEntitySets
where meta.ElementType.Name == entityTypeName
select meta.Name).FirstOrDefault();
}
#endregion
}
Notice that, here I also implement IDispose interface
to dispose the context
manually.To get the name of Entityset
, here I have used typeof
, but you can do a metadata query
to retrieve the EntitySet
name:
container = context.MetadataWorkspace.GetEntityContainer
(context.DefaultContainerName, DataSpace.CSpace);
string entitySetName = (from meta in container.BaseEntitySets
where meta.ElementType.Name == entityTypeName
select meta.Name).FirstOrDefault();
Here, I am not going a little into the code. I have used ObjectQuery
to get the features of MargeOption
and EnablePlanCaching
properties:
ObjectQuery.EnablePlanCaching
Property -indicates whether the query plan should be cached. Plan-caching caches information which is computed as part of putting together the query itself. By caching this, a subsequent execution of the same query (even if you change parameter values) will run much faster than the first one. This information is cached per app-domain
so you will generally benefit from the query cache across multiple client requests to the same web app and the like. Here all DoQuery
methods are responsible to queries and other query method like SelectAll
or Select
methods internally use these DoQuery
methods with various parameters.
Setting MergeOption
to NoTracking
has helped us to take advantage of the EF ability to return data that doesn’t need to be tracked by the context. Say I don’t have any plan to make changes to that data. Therefore, I like to avoid the performance hit taken when EF creates ObjectStateEntry
instances for each object it’s tracking, as well as forcing the context to be aware of any changes made to those objects.
SelectByKey
is creating a LINQ expression using Expression
tree for Primary key and while creating the repository on an entity, you can supply this Primary Key property as string
. While using the POCO as your entity, you can set attribute programming to serve this kind of job.
TrySameValueExist
is doing the same job by allowing you to set customize field and value comparison there. What it will do is create the E
xpression
for you and also add the PrimaryKey
comparison so that it excludes the object that you are querying for (and where PrimaryKey != currentObjectPrimaryKey
).
Add
and Delete
methods simply respectively call the AddObject
and DeleteObject
methods of ObjectContext
. AddOrAttach
method is for special situation where you don’t know whether object is already added or not. It is expensive since it will do query to database to check the existence.
The specification pattern
can implement a re-usable business logic component that can be passed around to satisfy certain business criteria. The specification
object has a clear and limited responsibility, which can be separated and decoupled from the domain object that uses it. I would highly recommend reading the white paper by Martin Fowler and Eric Evans on the Specification pattern.
public interface ISpecification<E>
{
/// <summary>
/// Select/Where Expression
/// </summary>
Expression<Func<E, bool>> EvalPredicate { get; }
/// <summary>
/// Function to evaluate where Expression
/// </summary>
Func<E, bool> EvalFunc { get; }
}
You can write your own specification
by implementing your interface
like RoleSpecification
and put down your business logic there. For general use, you can also implement the Interface;
such composite specification like this:
public class Specification<E> : ISpecification<E>
{
#region Private Members
private Func<E, bool> _evalFunc = null;
private Expression<Func<E, bool>> _evalPredicate;
#endregion
#region Virtual Accessors
public virtual bool Matches(E entity)
{
return _evalPredicate.Compile().Invoke(entity);
}
public virtual Expression<Func<E, bool>> EvalPredicate
{
get { return _evalPredicate; }
}
public virtual Func<E, bool> EvalFunc
{
get { return _evalPredicate != null ? _evalPredicate.Compile() : null; }
}
#endregion
#region Constructors
public Specification(Expression<Func<E, bool>> predicate)
{
_evalPredicate = predicate;
}
private Specification() { }
#endregion
#region Private Nested Classes
private class AndSpecification : Specification<E>
{
private readonly ISpecification<E> _left;
private readonly ISpecification<E> _right;
public AndSpecification(ISpecification<E> left, ISpecification<E> right)
{
this._left = left;
this._right = right;
this._evalFunc =
(Func<E, bool>)Delegate.Combine
(left.EvalPredicate.Compile(),
right.EvalPredicate.Compile());
_evalPredicate = left.EvalPredicate.And(right.EvalPredicate);
}
public override bool Matches(E entity)
{
return EvalPredicate.Compile().Invoke(entity);
}
}
private class OrSpecification : Specification<E>
{
private readonly ISpecification<E> _left;
private readonly ISpecification<E> _right;
public OrSpecification(ISpecification<E> left, ISpecification<E> right)
{
this._left = left;
this._right = right;
this._evalFunc =
(Func<E, bool>)Delegate.Combine
(left.EvalPredicate.Compile(),
right.EvalPredicate.Compile());
_evalPredicate = left.EvalPredicate.Or(right.EvalPredicate);
}
public override bool Matches(E entity)
{
return EvalPredicate.Compile().Invoke(entity);
}
}
#endregion
#region Operator Overloads
public static Specification<E> operator
&(Specification<E> left, ISpecification<E> right)
{
return new AndSpecification(left, right);
}
public static Specification<E> operator
|(Specification<E> left, ISpecification<E> right)
{
return new OrSpecification(left, right);
}
#endregion
}
Here, some operator overloading has been applied to combine the lambda expression (or predicate) of each specification
(left and right side of a composite specification) to create a new lambda expression.This new lambda expression is going to use for querying. So it will help you while you are working with multiple specification
already defined as your business rule.
To use this Repository
class from your business layer, one thing I must say is that I am sharing a single context
in the CRUD process/operation. You must keep alive the context in your entire process of a crud operation. For this, I make a UnitOfWork
on top of all.
public interface IUnitOfWork : IDisposable
{
IRepository<TSet> GetRepository<TSet>() where TSet : class;
DbTransaction BeginTransaction();
int Save();
}
Here, Unit of Work has been introduced as umbrella over multiple repositories and shared by all repositories in place of the object context directly and methods like save
, transaction
can be switched over there. And here is that implementation.
public class UnitOfWork<C> : IUnitOfWork where C : ObjectContext
{
private DbTransaction _transaction;
private Dictionary<Type, object> _repositories;
private C _ctx;
public UnitOfWork()
{
_ctx = Activator.CreateInstance<C>();
_repositories = new Dictionary<Type, object>();
}
public IRepository<TSet> GetRepository<TSet>() where TSet : class
{
if (_repositories.Keys.Contains(typeof(TSet)))
return _repositories[typeof(TSet)] as IRepository<TSet>;
var repository = new Repository<TSet, C>(_ctx);
_repositories.Add(typeof(TSet), repository);
return repository;
}
/// <summary>
/// Start Transaction
/// </summary>
/// <returns></returns>
public DbTransaction BeginTransaction()
{
if (null == _transaction)
{
if (_ctx.Connection.State != ConnectionState.Open)
{
_ctx.Connection.Open();
}
this._transaction = _ctx.Connection.BeginTransaction();
}
return _transaction;
}
public int Save()
{
return _ctx.SaveChanges();
}
#region IDisposable Members
public void Dispose()
{
if (null != _transaction)
{
_transaction.Dispose();
}
if (null != _ctx)
{
_ctx.Dispose();
}
}
#endregion
}
Repository
is kind of mediator to connect business layer with data access. So your business layer should be aware of this repository class. Now, In my BLLRoleManagement class
, say I have a method to delete User
. That will be something like this:
/// <summary>
/// Delete User
/// </summary>
/// <param name="userID">User ID</param>
/// <returns>True Or False</return>
public static bool DeleteUser(
string UserID)
{
try
{
var unitOfWork = new UnitOfWork<ProjectCodeEntities>();
var userRepository = unitOfWork.GetRepository<User>();
using (unitOfWork)
{
using (var transaction = unitOfWork.BeginTransaction())
{
User UserTobeRemoved = userRepository.SelectByKey(UserID);
if (UserTobeRemoved == null)
return false;
userRepository.DeleteRelatedEntries(UserTobeRemoved);
userRepository.Delete(UserTobeRemoved);
if (unitOfWork.Save() >= 0)
{
transaction.Commit();
return true;
}
}
}
}
catch (Exception ex)
{
throw ErrorHandler.WrapException(ex, ErrorCodes.DB_DeleteUser_Error_Code);
}
return false;
}
Here, it will initialize an ObjectContext
instance which will be used in your entire process/workflow of an operation. For this, I have provided a factory method inside Unit of Work which will create a repository for you using that ObjectContext
. Delete all related entities associated with User
and then delete User
. To share the same context
in this delete
process, I will call this method like this:
new BLLRoleManagement().DeleteUser(userID);
Surely, it has a lot of area to improve. I have used some interfaces here which can be used with dependency injection to decouple your code from EF. Hope it helps. So here is my end of the discussion on repository pattern implementation with Entity framework. Good luck!
References
History
- 10th June, 2009: Initial version