Ich versuche, meine Einheit der Arbeit von meinen Dienstleistungen oder Repository zu entkoppeln, so dass ich nicht der UOW-Code berühren müssen, wenn ich wünschen einen neuen Service
hinzufügen
Nun, das ist ein guter Anfang! ;-)
Die Lösung, die ich vorstelle, ist nicht die einzig mögliche Lösung, es gibt mehrere gute Möglichkeiten, UoW zu implementieren (Google wird Ihnen helfen). Aber das sollte dir das große Bild geben.
Erstellen Sie zunächst 2-Schnittstellen: IUnitOfWork und IRepository
public interface IUnitOfWork : System.IDisposable
{
IRepository<TEntity> GetRepository<TEntity>() where TEntity : class;
void Save();
}
public interface IRepository<T> : IDisposable where T : class
{
void Add(T entity);
void Delete(T entity);
void Update(T entity);
T GetById(long Id);
IEnumerable<T> All();
IEnumerable<T> AllReadOnly();
IEnumerable<T> Find(Expression<Func<T, bool>> predicate);
}
Die Implementierungen recht einfach sind (ich alle meine Kommentare zur besseren Lesbarkeit Zweck entfernt, aber vergessen Sie nicht verkaufen ;-) hinzufügen)
public class UnitOfWork<TContext> : IUnitOfWork where TContext : IDbContext, new()
{
private readonly IDbContext _ctx;
private Dictionary<Type, object> _repositories;
private bool _disposed;
public UnitOfWork()
{
_ctx = new TContext();
_repositories = new Dictionary<Type, object>();
_disposed = false;
}
public IRepository<TEntity> GetRepository<TEntity>() where TEntity : class
{
if (_repositories.Keys.Contains(typeof(TEntity)))
return _repositories[typeof(TEntity)] as IRepository<TEntity>;
var repository = new Repository<TEntity>(_ctx);
_repositories.Add(typeof(TEntity), repository);
return repository;
}
public void Save()
{
try
{
_ctx.SaveChanges();
}
catch (DbUpdateConcurrencyException ex)
{
ex.Entries.First().Reload();
}
}
…
}
public class Repository<T> : IRepository<T> where T : class
{
private readonly IDbContext _context;
private readonly IDbSet<T> _dbset;
public Repository(IDbContext context)
{
_context = context;
_dbset = context.Set<T>();
}
public virtual void Add(T entity)
{
_dbset.Add(entity);
}
public virtual void Delete(T entity)
{
var entry = _context.Entry(entity);
entry.State = EntityState.Deleted;
}
public virtual void Update(T entity)
{
var entry = _context.Entry(entity);
_dbset.Attach(entity);
entry.State = EntityState.Modified;
}
public virtual T GetById(long id)
{
return _dbset.Find(id);
}
public virtual IEnumerable<T> All()
{
return _dbset.ToList();
}
public virtual IEnumerable<T> AllReadOnly()
{
return _dbset.AsNoTracking().ToList();
}
public IEnumerable<T> Find(Expression<Func<T, bool>> predicate)
{
return _dbset.Where(predicate);
}
}
Wie Sie sehen können, verwenden beide Implementierungen die IDbContext-Schnittstelle. Diese Schnittstelle ist nur für einfache Testzwecke:
public interface IDbContext
{
DbSet<T> Set<T>() where T : class;
DbEntityEntry<T> Entry<T>(T entity) where T : class;
int SaveChanges();
void Dispose();
}
(Wie Sie sehen, ich bin mit EntityFramework-Code zuerst)
Nun, da die gesamte Sanitärbereich eingerichtet ist, werfen wir einen Blick darauf, wie diese könnte in einem Dienst verwendet werden. Ich habe einen Basisdienst, der wie folgt aussieht:
internal class Service<T> where T : class
{
internal Service(Infrastructure.IUnitOfWork uow)
{
_repository = uow.GetRepository<T>();
}
protected Infrastructure.IRepository<T> Repository
{
get { return _repository; }
}
private readonly Infrastructure.IRepository<T> _repository;
}
Und alle meine Dienste von dieser Basis-Service erben.
internal class CustomerService : Service<Model.Customer>
{
internal CustomerService(Infrastructure.IUnitOfWork uow) : base(uow)
{
}
internal void Add(Model.Customer customer)
{
Repository.Add(customer);
}
internal Model.Customer GetByID(int id)
{
return Repository.Find(c => c.CustomerId == id);
}
}
Und das ist es!
Nun, wenn du so teilen möchten gleich aussehen UOW auf mehrere Dienste in einer Fassade Methode oder irgendwo anders, es könnte nur:
using (var uow = new UnitOfWork<CompanyContext>())
{
var catService = new Services.CategoryService(uow);
var custService = new Services.CustomerService(uow);
var cat = new Model.Category { Name = catName };
catService.Add(dep);
custService.Add(new Model.Customer { Name = custName, Category = cat });
uow.Save();
}
hoffe, das hilft!
Können Sie mehr über Ihr Szenario erfahren? Es scheint mir, dass Sie über die Injektion von Abhängigkeit sprechen (Ihr Code hängt von ICategoryService ab und Sie möchten ihn automatisch injizieren), aber es ist nicht klar aus Ihrer Frage. –
Hallo! Ich habe ein MVC4-Testprojekt, um das UoW-Muster zu untersuchen. Ich habe einen Controller, eine Serviceklasse, die auf das Repository verweist. Aber wie Sie sehen können, habe ich diesen CategoryService in meiner UoW als Eigentum. Dann wurde mir klar, dass ich, wenn ich einen neuen Service für etwas in der Zukunft erstelle, diesen Dienst zu meiner UoW-Klasse hinzufügen müsste.Ich versuche, einen Weg zu finden, nur eine Get Funktion zu haben, die einen Diensttyp zurückgibt, der auf der Schnittstelle basiert, die ich ihm gab. Ich bin mir nicht einmal sicher, ob dies der richtige Weg ist. Vielen Dank! –
Was verwenden Sie für UoW-Container? Sie sollten einige der IoCs verwenden, überprüfen Sie diese Seite für schöne Liste: http://www.hanselman.com/blog/ListOfNETDependencyInjectionContainersIOC.aspx Die meisten von ihnen haben .Resolve() -Methode oder ähnliches, und Sie können die meisten von registrieren sie als Standard-Abhängigkeit Resolver in asp.net mvc, so fügen Sie einfach IService als Parameter zu Ihrem Controller. Fragen Sie das? –