I'm developing a web application in ASP.NET MVC with NHibernate.
Based in articles and tutorials I've found at Google, I'm using Repository for my classes.
I have 10 classes and 10 repositories. Today I figured out that 90% of mine repositories are exactly equal each other, except for the class. This is one example:
public class PromocaoRepository:IPromocaoRepository {
private ISession Session;
public PromocaoRepository() {
this.Session = NHibernateSessionFactory.OpenSession();
}
public void Add(Promocao promocao) {
using(ITransaction transaction = this.Session.BeginTransaction()) {
this.Session.Save(promocao);
transaction.Commit();
}
}
public void Edit(Promocao promocao) {
using(ITransaction transaction = this.Session.BeginTransaction()) {
this.Session.Update(promocao);
transaction.Commit();
}
}
public void Remove(Promocao promocao) {
using(ITransaction transaction = this.Session.BeginTransaction()) {
this.Session.Delete(promocao);
transaction.Commit();
}
}
public Promocao GetById(int id) {
return this.Session.Get<Promocao>(id);
}
}
There is a way to do a kind of generic repository witch I can use in all my classes?
If it's possible, what should I do in case I need to create a particular method for an specific class?
From another thread:
public interface IRepository<T> : IQueryable<T>
{
void Add(T entity);
T Get(Guid id);
void Remove(T entity);
}
public class Repository<T> : IQueryable<T>
{
private readonly ISession session;
public Repository(ISession session)
{
session = session;
}
public Type ElementType
{
get { return session.Query<T>().ElementType; }
}
public Expression Expression
{
get { return session.Query<T>().Expression; }
}
public IQueryProvider Provider
{
get { return session.Query<T>().Provider; }
}
public void Add(T entity)
{
session.Save(entity);
}
public T Get(Guid id)
{
return session.Get<T>(id);
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
public IEnumerator<T> GetEnumerator()
{
return session.Query<T>().GetEnumerator();
}
public void Remove(T entity)
{
session.Delete(entity);
}
}
Wrapping up nHibernate in repositories
That being said, you should take a look at S#arp Architecture, which already helps you with this repetitive process using Dependency Injection.
You should make a generic repository, which you can use in the general case, and if any extra methods is needed for a particular class, add it by using inheritance. Using your example:
public class GenericRepository<TEntity> :IGenericRepository<TEntity> {
private ISession Session;
public GenericRepository() {
this.Session = NHibernateSessionFactory.OpenSession();
}
public void Add(TEntity instance) {
using(ITransaction transaction = this.Session.BeginTransaction()) {
this.Session.Save(instance);
transaction.Commit();
}
}
/* other methods */
}
public class SpecificRepository : GenericRepository<SpecificEntity>, ISpecificRepository
{
public void SpecialQuery() { /* added method implementation */ }
}
Here is my answer to a similar question (28 votes as of right now):
Advantage of creating a generic repository vs. specific repository for each object?
The idea is to genericize the implementation, not the interface. Instead of an outward-facing generic repository interface, create an inward-facing generic repository base class, which you use to easily implement entity-specific interfaces.
Edit: I should point out that generic repositories serve a very different function than specific repositories. Repositories are intended to encapsulate the data access mechanisms behind the entity's queries, including all of the query logic. A generic repository encapsulates the ability to create queries, but it doesn't encapsulate any specific query about an entity.
The point is to not make repository consumers responsible for writing their own queries. A generic repository lives at the same level of abstraction as an ORM; a specific repository lives at a level above that.
Here's another example of a generic repository
Have a look at my answer to the question "Asp.net MVC 2 Entity Framework Generic Repository Method. how to Update a specific Collumn" - it should give you a good idea of what to do.
HTHs,
Charles
E.g.
Base model:
public interface IDbTable
{
int Id { get; set; }
DateTime DateCreated { get; set; }
DateTime DateUpdated { get; set; }
}
public class DbTable
{
public int Id { get; set; }
public DateTime DateCreated { get; set; }
public DateTime DateUpdated { get; set; }
}
Your model
public class Category : DbTable
{
public string Name { get; set; }
}
Your repository
public interface IBaseRepository<T> where T : class, IDbTable
{
void Add<T>(T entity);
void Edit<T>(T entity);
void Remove<T>(T entity);
T GetById(int id);
}
public class BaseRepository<T> : IBaseRepository<T>
{
private ISession Session;
public BaseRepository()
{
this.Session = NHibernateSessionFactory.OpenSession();
}
public void Add(T entity)
{
entity.DateCreated = DateTime.UtcNow;
entity.DateUpdated = DateTime.UtcNow;
using(ITransaction transaction = this.Session.BeginTransaction())
{
this.Session.Save(entity);
transaction.Commit();
}
}
public void Edit(T entity)
{
entity.DateUpdated = DateTime.UtcNow;
using(ITransaction transaction = this.Session.BeginTransaction())
{
this.Session.Update(entity);
transaction.Commit();
}
}
public void Remove(T entity)
{
using(ITransaction transaction = this.Session.BeginTransaction())
{
this.Session.Delete(entity);
transaction.Commit();
}
}
public T GetById(int id)
{
return this.Session.Get<T>(id);
}
}
Oh, and lets not forget the concrete implementation
public interface ICategoryRepository : IBaseRepository<Category>
{
Category GetCategoryByName(string categoryName);
}
public CategoryRepository : BaseRepository<Category>
{
public Category GetCategoryByName(string categoryName)
{
//blah
}
}
Related
I Have a PhoneBook Project in MVC and use IUnitOfWork .
but I dont Know that How do this project.
the link of the project :
http://www.mediafire.com/download/jy0b5ins5eisy5t/MvcAppPhoneBook.rar
please complate thie project for me
i'm doing CRUD in this project.
I've used generic repo and UoW in my projects as below. You can take reference of this to complete your project. I usually have 4 layer solution architecture:
Core
Model classes
Data
Generic Repo and UoW
DbContext
Code first migrations
Web
applications solution with dependency injection implementation (e.g.Ninject)
Test
Model classes
public class User
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Course
{
public int Id { get; set; }
public string Name { get; set; }
}
MyDbContext.cs:
public class MyDbContext : DbContext
{
public MyDbContext() : base("name=DefaultConnection”)
{
}
public System.Data.Entity.DbSet<User> Users { get; set; }
public System.Data.Entity.DbSet<Course> Courses { get; set; }
}
Unit of Work:
public class UnitOfWork : IUnitOfWork
{
//private variable for db context
private MyDbContext _context;
//initial db context variable when Unit of Work is constructed
public UnitOfWork()
{
_context = new MyDbContext();
}
//property to get db context
public MyDbContext Context
{
//if not null return current instance of db context else return new
get { return _context ?? (_context = new MyDbContext()); }
}
//save function to save changes using UnitOfWork
public void Save()
{
_context.SaveChanges();
}
}
Generic Repository:
public class RepositoryBase<T> : IRepositoryBase<T> where T : class
{
protected readonly IUnitOfWork _unitOfWork;
private readonly IDbSet<T> _dbSet;
public RepositoryBase(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
_dbSet = _unitOfWork.Context.Set<T>();
}
public virtual void Save()
{
_unitOfWork.Save();
}
public virtual void Add(T entity)
{
_dbSet.Add(entity);
_unitOfWork.Save();
}
//Similarly you can have Update(), Delete(), GetAll() implementation here
}
Entity Repository inheriting from generic repo:
public class UserRepository:RepositoryBase<User>,IUserRepository
{
public UserRepository(IUnitOfWork unitOfWork) : base(unitOfWork)
{
}
//Here you can also define functions specific to User
}
controller.cs
public class UserController : Controller
{
private readonly IUserRepository _dbUserRepository;
public UserController(IUserRepository dbUserRepository)
{
_dbUserRepository = dbUserRepository;
}
// GET: /User/
public ActionResult Index()
{
var users = _dbUserRepository.GetAll();
return View(users.ToList());
}
//Other CRUD operations
}
I'm using MVC pattern in my application. For each model class I have a controller one. All controller classes have a saveOrUpdate() method. I am wondering if this is enough to create an Interface which defines said method, and then all controller implements it.
Please note that saveOrUpdate() receive a model class as a parameter. So it would be something like UserController#saveOrUpdate(User user), CourseController#saveOrUpdate(Course course), AppleManager#saveOrUpdate(Apple apple).
I think what you need is generic repository which implements generic functionality for a given entity. I've recently started implementing Repository Pattern along with Unit of Work in my MVC projects. Here is how I do that.
MyDbContext.cs:
public class MyDbContext : DbContext
{
public MyDbContext() : base("name=DefaultConnection”)
{
}
public System.Data.Entity.DbSet<User> Users { get; set; }
public System.Data.Entity.DbSet<Course> Courses { get; set; }
}
Unit of Work:
public class UnitOfWork : IUnitOfWork
{
//private variable for db context
private MyDbContext _context;
//initial db context variable when Unit of Work is constructed
public UnitOfWork()
{
_context = new MyDbContext();
}
//property to get db context
public MyDbContext Context
{
//if not null return current instance of db context else return new
get { return _context ?? (_context = new MyDbContext()); }
}
//save function to save changes using UnitOfWork
public void Save()
{
_context.SaveChanges();
}
}
Generic Repository:
public class RepositoryBase<T> : IRepositoryBase<T> where T : class
{
protected readonly IUnitOfWork _unitOfWork;
private readonly IDbSet<T> _dbSet;
public RepositoryBase(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
_dbSet = _unitOfWork.Context.Set<T>();
}
public virtual void Save()
{
_unitOfWork.Save();
}
public virtual void Add(T entity)
{
_dbSet.Add(entity);
_unitOfWork.Save();
}
//Similarly you can have Update(), Delete(), GetAll() implementation here
}
Entity Repository inheriting from generic repo:
public class UserRepository:RepositoryBase<User>,IUserRepository
{
public UserRepository(IUnitOfWork unitOfWork) : base(unitOfWork)
{
}
//Here you can also define functions specific to User
}
Controller:
public class UserController : Controller
{
private readonly IUserRepository _dbUserRepository;
public UserController(IUserRepository dbUserRepository)
{
_dbUserRepository = dbUserRepository;
}
// GET: /User/
public ActionResult Index()
{
var users = _dbUserRepository.GetAll();
return View(users.ToList());
}
}
create an interface
interface ISave
{
void Save(object obj);
}
now in your controller implement it.
public class AppleControler : Controller , ISave
{
public void Save(Object obj)
{
//you can cast your object here.
}
}
Option two
interface ISave<T>
{
void Save(T obj);
}
public class AppleControler : Controller , ISave<Apple>
{
public void Save(Apple obj)
{
}
}
I have an asp.net mvc application where I use EF CodeFirst with a repository pattern and am trying to test and catch a DbUpdateConcurrencyException, but it doesn't appear to be firing, evening though when I update a record in one browser, while it is already open in another, and then go to the other and try to update the same record, it allows me to do it. I have a TimeStamp column on the table (called RowVersion) which does change with every update, so that is correct, and from watching sql profiler I can see the update statement does check that the timestamp is what is being passed in, so I'm out of ideas, and am unable to find anything so far to really help me. If anyone can see something I am doing wrong, please let me know. Thanks!!
Here is my entity:
public class MyEntity : EntityBase
{
public override int Id { get; set; }
public DateTime? LastEdited { get; set; }
[Timestamp]
public byte[] RowVersion { get; set; }
}
Here is the repository and it's base classes/dbcontext:
public class MyEntityDataProvider : EfDataProviderBase<MyEntity>, IMyEntityDataProvider
{
public MyEntityDataProvider (IDataContext dataContext) : base(dataContext) { }
}
public abstract class EfDataProviderBase<T> : DataProviderBase<T> where T : EntityBase
{
public new DbDataContext DataContext
{
get { return base.DataContext as DbDataContext; }
protected set { base.DataContext = value; }
}
public EfDataProviderBase(IDataContext dataContext)
: base(dataContext)
{
if (!(dataContext is DbDataContext)) throw new ArgumentException("Parameter 'dataContext' must be of type DbDataContext.");
}
public override T GetById(int id)
{
if (id < 1) return null;
return this.DataContext.GetDbSet<T>().Find(id);
}
public override List<T> GetAll()
{
return this.DataContext.GetDbSet<T>().OrderBy(e => e.Id).ToList();
}
public override void Insert(T entity)
{
if (entity == null) throw new ArgumentNullException("entity");
this.DataContext.GetDbSet<T>().Add(entity);
}
public override void Update(T entity)
{
if (entity == null) throw new ArgumentNullException("entity");
if (!this.DataContext.GetDbSet<T>().Local.Any(e => e.Id == entity.Id))
this.DataContext.GetDbSet<T>().Attach(entity);
this.DataContext.Entry(entity).State = EntityState.Modified;
}
}
public class DbDataContext : DbContext, IDataContext
{
public DbSet<MyEntity> MyEntities { get; set; }
public DbSet<T> GetDbSet<T>() where T : EntityBase
{
Type entityType = typeof(T);
if (entityType == typeof(User))
return this.Users as DbSet<T>;
}
public void Commit()
{
this.SaveChanges();
}
}
public abstract class DataProviderBase<T> : IDataProvider<T> where T: EntityBase
{
public IDataContext DataContext { get; protected set; }
public DataProviderBase(IDataContext dataContext)
{
if (dataContext == null) throw new ArgumentNullException("dataContext");
this.DataContext = dataContext;
}
public abstract T GetById(int id);
public abstract List<T> GetAll();
public void Save(T entity)
{
if (entity == null) throw new ArgumentNullException("entity");
if (entity.IsNew)
{
this.Insert(entity);
}
else if (entity.IsDeleted)
{
this.Delete(entity);
}
else
{
this.Update(entity);
}
}
public abstract void Insert(T entity);
public abstract void Update(T entity);
}
Here is my controller action:
[HttpPost]
[ValidateAntiForgeryToken()]
public ActionResult UpdateViewModel(ViewModel model)
{
if (ModelState.IsValid)
{
try
{
MyEntity current = this.MyEntityDataProvider.GetById(model.Id);
current.LastEdited = DateTime.UtcNow;
current.RowVersion = model.Timestamp; // should have original timestamp, getting from hidden field on view
this.MyEntityDataProvider.Save(current);
this.DataContext.Commit(); // one dbcontext per http request, injected by ninject
return Json(new { success = "Saved!" });
}
catch (DbUpdateConcurrencyException)
{
ModelState.AddModelError("", "This record has been edited by an another person since you have opened it - please close and re-open to attempt your changes again.");
}
}
return Json(new { errors = GetErrorsFromModelState() });
}
Good morning friend.
You should add information on the property you want to control concurrency.
Example:
[ConcurrencyCheck]
public int Code {get; set;}
Lets say I have 2 tables. ProductCategory and Product. I have 1 generic repository that can handle both tables:
public class GenericRepository<T> : IRepository<T>
But when using unit of work pattern, am I forced to create a repository for ALL tables in my database?
public interface IUnitOfWork : IDisposable
{
int SaveChanges();
IRepository<ProductCategory> ProductCategoryRepository { get; }
IRepository<Product> ProductRepository { get; }
}
Is there not a way I can add the generic repository to the unit of work class?
You can add a generic method to the IUnitOfWork interface:
public interface IUnitOfWork : IDisposable
{
int SaveChanges();
IRepository<T> Repository<T>();
}
But i don't recommend it. It's smells like Service Locator anti-pattern and SRP violation. Better way is to remove all repositories from the IUnitOfWork interface, because providing access to repository is not UnitOfWork's responsibility. I recommend to separate repository from UnitOfWork and inject their into the consumer by itself.
public class Consumer
{
private readonly IUnitOfWork _unitOfWork;
private readonly IRepository<Product> _products;
public Consumer(IUnitOfWork unitOfWork, IRepository<Product> products)
{
_unitOfWork = unitOfWork;
_products = products;
}
public void Action()
{
var product = _products.GetOne();
product.Name = "new name";
_products.Update(product);
_unitOfWork.SaveChanges();
}
}
UDATE:
UnitOfWork and Repository can share context instance.
Here the sample of code:
public class EfUnitOfWork : IUnitOfWork
{
private readonly DbContext _context;
public EfUnitOfWork(DbContext context)
{
_context = context;
}
public void SaveChanges()
{
_context.SaveChanges();
}
}
public class EfRepository<T> : IRepository<T> where T : class
{
private readonly DbContext _context;
public EfRepository(DbContext context)
{
_context = context;
}
//... repository methods...
}
public class Program
{
public static void Main()
{
//poor man's dependency injection
var connectionString = "northwind";
var context = new DbContext(connectionString);
var unitOfWork = new EfUnitOfWork(context);
var repository = new EfRepository<Product>(context);
var consumer = new Consumer(unitOfWork, repository);
consumer.Action();
}
}
Demonstrating a solution with only one class would be
public class Session : ISession
{
private readonly DbContext _dbContext;
public Session(DbContext dbContext)
{
_dbContext = dbContext;
}
public TEntity Single<TEntity>(Expression<Func<TEntity, bool>> expression) where TEntity : class
{
return _dbContext.Set<TEntity>().SingleOrDefault(expression);
}
public IQueryable<TEntity> Query<TEntity>() where TEntity : class
{
return _dbContext.Set<TEntity>().AsQueryable();
}
public void Commit()
{
try { _dbContext.SaveChanges(); }
catch (DbEntityValidationException ex)
{
var m = ex.ToFriendlyMessage();
throw new DbEntityValidationException(m);
}
}
public void Dispose()
{
_dbContext.Dispose();
}
public void Add<TEntity>(IEnumerable<TEntity> items) where TEntity : class
{
items.ToList().ForEach(Add);
}
public void Add<TEntity>(TEntity item) where TEntity : class
{
_dbContext.Set<TEntity>().Add(item);
}
public void Remove<TEntity>(TEntity item) where TEntity : class
{
_dbContext.Set<TEntity>().Remove(item);
}
public void Remove<TEntity>(Expression<Func<TEntity, bool>> expression) where TEntity : class
{
var items = Query<TEntity>().Where(expression);
Remove<TEntity>(items);
}
public void Remove<TEntity>(IEnumerable<TEntity> items) where TEntity : class
{
items.ToList().ForEach(Remove);
}
}
and then your usage can be
public class User
{
public int? Id { get; set; }
public string Name { get; set; }
public DateTime Dob { get; set; }
}
public class Usage
{
private readonly ISession _session;
public Usage(ISession session) { _session = session; }
public void Create(User user)
{
_session.Add(user);
_session.Commit();
}
public void Update(User user)
{
var existing = _session.Single<User>(x => x.Id == user.Id);
// this gets cumbursome for an entity with many properties.
// I would use some thing like valueinjecter (nuget package)
// to inject the existing customer values into the one retreived from the Db.
existing.Name = user.Name;
existing.Dob = user.Dob;
_session.Commit();
}
}
I have deliberately not included a Repository class. To have a class encapsulate both queries and commands for every entity is an over kill and a needless abstraction. Its almost a design flaw at a fundamental level. Queries and commands are fundamentally different concerns. Queries in the most simplest manner can be created as extensions methods on the ISession interface. Commands can be done using a few classes like such..
public interface ICommand<in TSource>
{
void ApplyTo(TSource source);
}
public interface ICommandHandler<out TSource>
{
void Handle(ICommand<TSource> command);
}
public class LinqCommandHandler : ICommandHandler<IStore>
{
private readonly ISession _session;
public LinqCommandHandler(ISession session)
{
_session = session;
}
public void Handle(ICommand<IStore> command)
{
command.ApplyTo(_session);
_session.Commit();
}
}
public class UpdateDobForUserName : ICommand<IStore>
{
public string UserName { get; set; }
public DateTime Dob { get; set; }
public void OnSend(IStore store)
{
var existing = store.Query<User>().SingleOrDefault(x => x.Name == UserName);
existing.Dob = Dob;
}
}
public class Usage
{
private readonly ICommandHandler<IStore> _commandHandler;
public Usage(ICommandHandler<IStore> commandHandler)
{
_commandHandler = commandHandler;
}
public void Update()
{
var command = new UpdateDobForUserName {UserName = "mary", Dob = new DateTime(1960, 10, 2)};
_commandHandler.Handle(command);
}
}
The IStore above is the same as the Session class, except that it doesn't implement the IDisposable interface and doesn't have a Commit() method. The ISession then obviously inherits from an IStore and also implements IDisposable and has one method Commit(). This ensures an ICommand<IStore> can never open or dispose connections and cannot commit. Its responsibility is to define a command and define how its applied. Who applies it and what happens and what not on command application is a different responsibility which is with the ICommandHandler<IStore>.
There are many ways to implement Unit of work. I prefer having the repositories take a Unit of Work in its constructor (which is passed via Dependency Injection), then you only create repositories for your needs.
If I have the following setup, how can I configure my container to use the same database, when objects are created in the same context
public class Database { }
public interface IRepository { Database Database { get; } }
public interface IFooRepository : IRepository { }
public interface IBarRepository : IRepository { }
public class FooRepository : IFooRepository
{
public Database Database { get; private set; }
public FooRepository(Database database) { this.Database = database; }
}
public class BarRepository : IBarRepository
{
public Database Database { get; private set; }
public BarRepository(Database database) { this.Database = database; }
}
public class Consumer
{
public IFooRepository fooRepository { get; private set; }
public IBarRepository barRepository { get; private set; }
public Consumer(IFooRepository fooRepository, IBarRepository barRepository)
{
this.fooRepository = fooRepository;
this.barRepository = barRepository;
}
}
[TestClass]
public class ConfigurationTest
{
private IWindsorContainer container;
[TestMethod]
public void SameDatabaseIsUsed()
{
Consumer consumer = container.Resolve<Consumer>();
IFooRepository fooRepository = consumer.fooRepository;
IBarRepository barRepository = consumer.barRepository;
Assert.AreEqual(fooRepository.Database, barRepository.Database); //FAILS
}
[TestMethod]
public void DifferentDatabaseIsUsed()
{
Consumer consumer = container.Resolve<Consumer>();
IFooRepository fooRepository = consumer.fooRepository;
Consumer consumer2 = container.Resolve<Consumer>();
IBarRepository barRepository = consumer2.barRepository;
Assert.AreNotEqual(fooRepository.Database, barRepository.Database); //PASSES
}
[TestInitialize]
public void SetUp()
{
container = new WindsorContainer();
container.Register(
Component.For<Database>().ImplementedBy<Database>().LifeStyle.Transient,
AllTypes.FromThisAssembly()
.BasedOn<IRepository>().WithService.FromInterface()
.Configure(c => c.LifeStyle.Transient),
Component.For<Consumer>().ImplementedBy<Consumer>().LifeStyle.Transient
);
}
}
EDIT:
I have tried to use a custom lifestyle, but i cannot figure out what I can use to detect that i have switched context
public class DatabaseLifestyleManager : AbstractLifestyleManager
{
private CreationContext context;
private Database database;
private Database Database
{
get
{
if (database == null) database = new Database();
return database;
}
set
{
database = null;
}
}
public override object Resolve(CreationContext context)
{
if (this.context!=null && this.context.??? == context.???)
return Database;
else
{
this.context = context;
Database = null;
return Database;
}
}
public override void Dispose()
{
database = null;
context = null;
}
}
......
Component.For<Database>().ImplementedBy<Database>().LifeStyle.Custom(typeof(DatabaseLifestyleManager)
You always get a new instance when requesting a transient component, if it's not what you want don't use the transient lifestyle :-)
Why would you register a transient component, but attempt to resolve the same object depending on some kind of "context"? Most likely the lifestyle is wrong for the situation, and you will be in trouble trying to coerce it into something it's not.
What you want is something like a contextual lifestyle, mentioned in this article.
The below two gists have an implementation for this:
http://gist.github.com/400979
http://gist.github.com/400980
This will allow you do this:
Register(Component.For<Database>().LifeStyle.Scoped())
[TestMethod]
public void SameDatabaseIsUsed()
{
using (container.BeginScope())
{
Consumer consumer = container.Resolve<Consumer>();
IFooRepository fooRepository = consumer.fooRepository;
IBarRepository barRepository = consumer.barRepository;
Assert.AreEqual(fooRepository.Database, barRepository.Database); // YAY!
}
}
Hope this helps!
A contextual lifestyle is included in the Castle.Windsor.Lifestyles contrib project.
I came up with this solution myself by implementing IDisposable, so that I can use a kind of sessionscope for the Database
Would this be a valid way to handle this situation?
All test passes, but there is some added functionality, that must be implemented in all my future consumers of the repositories:
public class Database { }
public interface IRepository : IDisposable { Database Database { get; } }
public interface IFooRepository : IRepository { }
public interface IBarRepository : IRepository { }
public abstract class BaseRepository : IDisposable
{
public BaseRepository(Database database) { this.Database = database; }
public Database Database { get; private set; }
public void Dispose() { Database = null; }
}
public class FooRepository : BaseRepository, IFooRepository
{
public FooRepository(Database database) : base(database) { }
}
public class BarRepository : BaseRepository, IBarRepository
{
public BarRepository(Database database) : base(database) { }
}
public abstract class BaseConsumer : IDisposable
{
public abstract void Dispose();
}
public class Consumer : BaseConsumer
{
public IFooRepository fooRepository { get; private set; }
public IBarRepository barRepository { get; private set; }
public Consumer(IFooRepository fooRepository, IBarRepository barRepository)
{
this.fooRepository = fooRepository;
this.barRepository = barRepository;
}
public override void Dispose()
{
this.fooRepository.Dispose();
this.barRepository.Dispose();
}
}
[TestClass]
public class ConfigurationTest
{
private IWindsorContainer container;
[TestMethod]
public void SameDatabaseIsUsed()
{
IFooRepository fooRepository;
IBarRepository barRepository;
using (Consumer consumer = container.Resolve<Consumer>())
{
fooRepository = consumer.fooRepository;
barRepository = consumer.barRepository;
Assert.AreEqual(fooRepository.Database, barRepository.Database); //FAILS
}
Assert.IsNull(fooRepository.Database);
Assert.IsNull(barRepository.Database);
}
[TestMethod]
public void DifferentDatabaseIsUsed()
{
IFooRepository fooRepository;
IBarRepository barRepository;
using (Consumer consumer = container.Resolve<Consumer>())
fooRepository = consumer.fooRepository;
Assert.IsNull(fooRepository.Database);
using (Consumer consumer2 = container.Resolve<Consumer>())
barRepository = consumer2.barRepository;
Assert.IsNull(barRepository.Database);
}
[TestInitialize]
public void SetUp()
{
container = new WindsorContainer().Register(
Component.For<Database>().ImplementedBy<Database>().LifeStyle.Singleton,
AllTypes.FromThisAssembly()
.BasedOn<IRepository>().WithService.FromInterface()
.Configure(c => c.LifeStyle.Transient),
Component.For<Consumer>().ImplementedBy<Consumer>().LifeStyle.Transient
);
}
}