patterncsharpMinor
Mix of Repository and UOW For Business Library with Entity Per Table Architecture
Viewed 0 times
mixarchitectureuowbusinessperwithforrepositorylibraryand
Problem
I am trying to use Entity framework along with UOW in business class where I want to use this layer across multiple types of applications like web, webapi and Windows Services. So I cooked something from the online resources. Can some one figure out any potential performance or fallback?
Main reason I am trying to write this way is to use this across multiple application layers with out dealing Entities across them. Now all I have to do is add reference to the application and use them as written at the bottom.
```
public interface IUnitOfWork : IDisposable
{
///
/// Call this to commit the unit of work
///
void Commit();
///
/// Return the database reference for this UOW
///
DbContext Db { get; }
///
/// Starts a transaction on this unit of work
///
void StartTransaction();
}
public interface IBaseRepository
{
///
/// Retrieve a single item using it's primary key, exception if not found
///
/// The primary key of the record
/// T
T Single(object primaryKey);
///
/// Retrieve created by and modified by id's FullName
///
/// The primary key of the record
/// T
Dictionary GetAuditNames(dynamic dynamicObject);
///
/// Retrieve a single item by it's primary key or return null if not found
///
/// Prmary key to find
/// T
T SingleOrDefault(object primaryKey);
///
/// Returns all the rows for type T
///
///
IEnumerable GetAll();
///
/// Does this item exist by it's primary key
///
///
///
bool Exists(object primaryKey);
///
/// Inserts the data into the table
///
/// The entity to insert
/// The user performing the insert
///
void Insert(T entity);
Main reason I am trying to write this way is to use this across multiple application layers with out dealing Entities across them. Now all I have to do is add reference to the application and use them as written at the bottom.
```
public interface IUnitOfWork : IDisposable
{
///
/// Call this to commit the unit of work
///
void Commit();
///
/// Return the database reference for this UOW
///
DbContext Db { get; }
///
/// Starts a transaction on this unit of work
///
void StartTransaction();
}
public interface IBaseRepository
{
///
/// Retrieve a single item using it's primary key, exception if not found
///
/// The primary key of the record
/// T
T Single(object primaryKey);
///
/// Retrieve created by and modified by id's FullName
///
/// The primary key of the record
/// T
Dictionary GetAuditNames(dynamic dynamicObject);
///
/// Retrieve a single item by it's primary key or return null if not found
///
/// Prmary key to find
/// T
T SingleOrDefault(object primaryKey);
///
/// Returns all the rows for type T
///
///
IEnumerable GetAll();
///
/// Does this item exist by it's primary key
///
///
///
bool Exists(object primaryKey);
///
/// Inserts the data into the table
///
/// The entity to insert
/// The user performing the insert
///
void Insert(T entity);
Solution
I think it's wrong. Your entity types are mixing concerns and are no longer simple POCO types, they now have incestuous knowledge of a
Not only that, but you're working against Entity Framework, rather than with it: a
Consider:
A
Needing a
Your "abstract unit of work" isn't an
Entity types should be Plain Old CLR Objects - simple classes with getters+setters; yours are full-fledged data access services, and to be honest I'm surprised Entity Framework can even work with those, given the absence of a default constructor and... the singleton.
How are you supposed to have an
How does this even compiles without a default constructor?
I'm guessing the default constructor is defined by the EDMX generated code, otherwise your code would never work. Point is, if a type has to have a default constructor, even considering making a singleton out of it is pointless.
Split responsibilities, let entity types be entity types, and write your
That way whoever is controlling the instantiation of
DbContext (which can access every single entity type and the database itself, run stored procedures, ...everything).Not only that, but you're working against Entity Framework, rather than with it: a
DbContext is a unit-of-work, as it already encapsulates a transaction for you - and regardless of what people say, IDbSet is a repository, at least as far as EF is concerned.Consider:
public interface IUnitOfWork : IDisposable
{
void Commit();
IDbSet Repository();
}A
DbContext can very easily implement that interface:public class MyDbContext : DbContext, IUnitOfWork
{
/* ...implementation details... */
public IDbSet Repository()
{
return Set();
}
public void Commit()
{
SaveChanges();
}
}Needing a
StartTransaction method on a UoW feels weird at best, because the sole purpose of a UoW is to encapsulate a transaction - in an ideal world, you would only call SaveChanges once in its entire lifetime.Your "abstract unit of work" isn't an
abstract class, which makes things confusing.Entity types should be Plain Old CLR Objects - simple classes with getters+setters; yours are full-fledged data access services, and to be honest I'm surprised Entity Framework can even work with those, given the absence of a default constructor and... the singleton.
How are you supposed to have an
IEnumerable if TEntity is a singleton?How does this even compiles without a default constructor?
MyClass newInstance = new MyClass();I'm guessing the default constructor is defined by the EDMX generated code, otherwise your code would never work. Point is, if a type has to have a default constructor, even considering making a singleton out of it is pointless.
Split responsibilities, let entity types be entity types, and write your
GetFooByBar methods in some FooService class that receives an IUnitOfWork dependency in its constructor:public class SomeService
{
private readonly IUnitOfWork _uow;
public SomeService(IUnitOfWork uow)
{
_uow = uow;
}
public SomeEntity GetById(int id)
{
return _uow.Repository().SingleOrDefault(e => e.Id == id);
}
// ...
}That way whoever is controlling the instantiation of
SomeService gets to inject the IUnitOfWork, and if there are 20 such services, they can all get the same instance, and thus contribute to the same transaction.Code Snippets
public interface IUnitOfWork : IDisposable
{
void Commit();
IDbSet<T> Repository<T>();
}public class MyDbContext : DbContext, IUnitOfWork
{
/* ...implementation details... */
public IDbSet<T> Repository<T>()
{
return Set<T>();
}
public void Commit()
{
SaveChanges();
}
}MyClass newInstance = new MyClass();public class SomeService
{
private readonly IUnitOfWork _uow;
public SomeService(IUnitOfWork uow)
{
_uow = uow;
}
public SomeEntity GetById(int id)
{
return _uow.Repository<SomeEntity>().SingleOrDefault(e => e.Id == id);
}
// ...
}Context
StackExchange Code Review Q#140870, answer score: 3
Revisions (0)
No revisions yet.