I have the following repository interface
public interface IRepository<TEntity> {
TEntity FindById(int id);
TEntity FindById(long id);
etc
}
I then have the following Repository class that inherits from the interface above
public class Repository<TEntity> : IRepository<TEntity> where TEntity : class {
private DB _context;
public Repository() {
_context = new DB();
}
public Repository(DB context) {
_context = context;
}
Methods.....
}
I have created a FakeRepository<> that also inherits from IRepository<>
public class FakeRepository<TEntity> : IRepository<TEntity> where TEntity : class {
private FakeDataContext _context;
public FakeRepository() {
_context = new FakeDataContext();
}
public FakeRepository(FakeDataContext context) {
_context = context;
}
Methods....
}
The only difference between the Repository and the Fake is that rather than using the LinqToSQL DBContext I have created a fake one for testing purposes.
What I then what to be able to do in my unit tests is:
ObjectFactory.Initialize(x => { x.For(typeof(Repository<>)).Use(typeof(FakeRepository<>)); });
So my tests will always be run against the in-memory fakedbcontext.
However I get structuremap error 104 pluggin type error and i'm not sure why?
In your Initialize you should map IRepository against FakeRepository. Not Repository against FakeRepository. Then in your tests when you ask for an instance of IRepository you will get the fake one.
ObjectFactory.Initialize(x => { x.For(typeof(IRepository<>)).Use(typeof(FakeRepository<>)); });
Why you don't use Dev Magic Fake, it has Fake the repository with many features like, save any type retrieve any type with Id, it can save the type permanent through serialization the memory, it also can generate data for your types and many other features for more information you can see the following link:
http://devmagicfake.codeplex.com/
Thanks
M.Radwan
Related
Is it possible to do something like this?
Query.cs
class Query<T> : ObjectType<MyQuery<T>> where T : class
{
protected override void configure(IObjectTypeDescriptor<MyQuery<T>> descriptor)
{
descriptor
.Field(f => f.GetItems)
.Description("Return List");
}
}
public partial class MyQuery<T> where T : class
{
private readonly IGenericRepositorty _repo
public MyQuery(IGenericRepositorty repo)
{
_repo = repo;
}
public IEnumerable<T> GetItems()
{
return _repo.GetAll(); // GetAll in generic repo
}
}
Now if I am adding my service in Startup.cs as
services.AddQueryType<MyQuery<Entity>>();
It works.
But I want to add it as
services.AddQueryType<MyQuery<>>(); or kind of services.AddQueryType(typeOf(MyQuery<>));
The way we inject generic repo like this
services.AddScoped(typef(IGenericRepository<>),typeofGenericRepository<>)
So, here at run time it creates an instance.
The same way for query at run time I am trying whether it will be possible to create instance
I am building an application (a web api to be specific) and I want to implement the repository pattern to abstract the data access layer and prepare it for future changes.
My goal is to make the repositories interfaces abstract enough to be able to implement every technology on top of them, starting from Native SQL Client (running sql command) to orm's like EF or dapper.
I have read some articles about repositories and the interface of my generic repository looks something like that:
interface IRepository<T>
{
IEnumerable<T> FindAll();
IEnumerable<T> FindBy(Expression<Func<T, bool>> predicate);
T FindById(int id);
void Add(T entity);
void Remove(T entity);
}
I want the method FindBy to accept a linq expression because the other option is making it accept native sql and that won't work too well with technologies like linq to entity of EF.
The problem is that i also want to be able to implement a native sql repository on top of this interface and in order to implement a native sql repository, i need to run sql command, strings.
In this interface i don't accept any sql command as string, i accept linq expressions, and the native sql client can't handle linq expressions (as far as i know).
So my question is, how can i make this interface be compatible with any technology/orm/library/client/adapter, you get the idea...
Thanks,
Arik
Adbstracting repository is a good idea. I'll try to help you.
First of all, your repository must independent of persistance, so you need to remove method FindBy(Expression<Func<T, bool>> predicate), rather replace it with some kind of specification pattern:
interface IRepository<T>
{
IEnumerable<T> FindAll();
IEnumerable<T> FindBy(ISpecification<T> specification);
T FindById(int id);
void Add(T entity);
void Remove(T entity);
}
public interface ISpecification<T>
{
IEnumerable<T> Execute(DbContext context);
}
So, now we have independent repository. And then you can create implementation of specification and repository for linq-supported persistance, it can looks like this:
public class LinqRepository<T> : IRepository<T>
{
private readonly DbContext _context;
public LinqRepository(DbContext context)
{
_context = context;
}
public IEnumerable<T> FindBy(ISpecification<T> specification)
{
return specification.Execute(_context);
}
//and others...
}
public class LinqSpecification<T> : ISpecification<T>
{
private readonly Expression<Func<T, bool>> _predicate;
public LinqSpecification(Expression<Func<T, bool>> predicate)
{
this._predicate = predicate;
}
public IEnumerable<T> Execute(DbContext context)
{
return context.Set<T>().Where(_predicate).ToList();
}
}
And call like this:
IRepository<Person> repository = new LinqRepository<Person>(dbContext);
var adults = repository.FindBy(new LinqSpecification<Person>(p => p.Age > 18));
Another side, when you need to implement non-linq repository, it can look like this:
public class SqlRepository<T> : IRepository<T>
{
private readonly DbContext _context;
public SqlRepository(DbContext context)
{
_context = context;
}
public IEnumerable<T> FindBy(ISpecification<T> specification)
{
return specification.Execute(_context);
}
}
public class SqlSpecification<T> : ISpecification<T>
{
private readonly string _query;
public SqlSpecification(string query)
{
_query = query;
}
public IEnumerable<T> Execute(DbContext context)
{
return context.ExecuteSql<T>(_query);
}
}
And call:
IRepository<Person> repository = new SqlRepository<Person>(dbContext);
var adults = repository.FindBy(new SqlSpecification<Person>("SELECT * FROM Persons WHERE Age > 18"));
Of couse, it's not ideal variant, but it depends on your system architecture and other components. But it can be used as background.
Hi I am trying to change a code example found here
http://imar.spaanjaars.com/577/aspnet-n-layered-applications-implementing-a-repository-using-ef-code-first-part-5
In his example he uses structure map, when I converted it to windsor I can get it to work with the one repository using the following.
container.Register(Component.For<IUnitOfWorkFactory>().ImplementedBy<EFUnitOfWorkFactory>(),
Component.For<IUnitOfWork>().ImplementedBy<EFUnitOfWork>(),
Component.For<Model.Repositories.IPeopleRepository>().ImplementedBy<PeopleRepository>().LifestyleTransient());
But what I really want to do is to map all the irepository based interfacees to thier implementation.
Here is the IRepository, T is the entity, K is the prmiary key type
public interface IRepository<T, K> where T : class
{
}
Its implementation Is
public abstract class Repository<T> : IRepository<T, int>, IDisposable where T : DomainEntity<int>
{
}
My controller has the interface IPeopleRepository as a constructor paramerter.
public interface IPeopleRepository : IRepository<Person, int>
{
}
public class PeopleRepository : Repository<Person>, IPeopleRepository
{
}
I want to have one register to register all repositories, something like this, but it wont match and i get the error Service 'Spaanjaars.ContactManager45.Model.Repositories.IPeopleRepository' which was not registered
container.Register(Component.For(typeof(IRepository<,>))
.ImplementedBy(typeof(Repository<>))
.LifestylePerWebRequest());
What am i missing in regards to this? is it because my irepository has 2 generic types?
In order to map all the IRepository based interfaces to their implementations .WithService.AllInterfaces() should be used.
This registration should solve your issue.
container.Register(
Classes.FromThisAssembly()
.BasedOn(typeof(IRepository<,>))
.WithService.AllInterfaces()
.LifestylePerWebRequest());
There are some tests to test it. I claim they are green.
[TestClass]
public class InstallerTest
{
private IWindsorContainer container;
[TestInitialize]
public void Init()
{
container = new WindsorContainer().Install(new Installer());
}
[TestMethod]
public void ResilveTest_ResolvesViaIRepository()
{
// act
var repository = container.Resolve<IRepository<Person, int>>();
// assert
repository.Should().BeOfType<PeopleRepository>();
}
[TestMethod]
public void ResilveTest_ResolvesViaIPeopleRepository()
{
// act
var repository = container.Resolve<IPeopleRepository>();
// assert
repository.Should().BeOfType<PeopleRepository>();
}
}
public class Installer : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
Classes.FromThisAssembly()
.BasedOn(typeof(IRepository<,>))
.WithService.AllInterfaces()
.LifestylePerThread());
}
}
Im very new but on a quest to learn nhibernate and DI with structuremap so am making an app to test everything out.
I am having some problems injecting my unitofwork into my base repository. I create a unitofwork on every request then either commit or rollback at the end. But when tryin to inject into my base repository its always null when i go to use it in my methods. More specifically i get this error: "Object reference not set to an instance of an object". Any ideas what im doing wrong and if this is the correct route i should be going?
Many thanks in advance.
Base Repository:
public abstract class Repository<T> : IRepository<T>
{
public readonly IUnitOfWork _unitOfWork;
public Repository(IUnitOfWork UnitOfWork)
{
UnitOfWork = _unitOfWork;
}
public Repository() {}
public void Save(T obj)
{
_unitOfWork.CurrentSession.Save(obj);
}
}
StructureMap registry thats set in my application_start:
public class NHibernateRegistry : Registry
{
public NHibernateRegistry()
{
For<IUnitOfWork>().HybridHttpOrThreadLocalScoped().Use<UnitOfWork>();
For<ISession>().HybridHttpOrThreadLocalScoped().Use(context => context.GetInstance<ISessionFactory>().OpenSession());
For<ISessionFactory>().Singleton().Use(NHibernateSessionFactory.GetSessionFactory());
}
}
Update:
The baserepository is inherited by specific repositorys ie ArticleRepository then im injecting that into my aspx pages on application_start. Then my aspx page inherits a basepage where the buildUp takes place. And i access the repository like this:
public IArticleRepository ArticleRepo { get; set; }
public void SaveThing()
{
ArticleRepo.Save(object);
}
This gets called on application_start:
public class Bootstrapper
{
public static void BootStrap()
{
ObjectFactory.Configure(x =>
{
x.AddRegistry<NHibernateRegistry>();
x.AddRegistry<WebRegistry>();
});
}
}
And in the webregistry:
For<IArticleRepository>().Use<ArticleRepository>();
There is a good chance your ArticleRepository doesn't have a constructor that takes an IUnitOfWork as a parameter make sure you have the following
public class ArticleRepository : Repository<Article>
{
public ArticleRepository(IUnitOfWork unitOfWork) : base(unitOfWork)
{
}
...
}
Remember Strcuture map uses the greediest constructor on the class that it instantiates. Since your abstract repository class will never be instantiated it will not use its constructors. I would also suggest not having any default constructors if your classes need to have their dependencies injected that way. Less chance for errors that way.
public readonly IUnitOfWork _unitOfWork;
public Repository(IUnitOfWork UnitOfWork)
{
UnitOfWork = _unitOfWork;
}
I think you mean to write
public readonly IUnitOfWork _unitOfWork;
public Repository(IUnitOfWork UnitOfWork)
{
_unitOfWork = UnitOfWork;
}
You were assigning the local variable to the parameter instead of the parameter to the local variable.
Edit: Also you should write your parameter with a lowercase U 'unitOfWork' instead of 'UnitOfWork'
In my MVC project, I have setup my MvcApplication_start() :
ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory());
And have successfully bound an .To regarding my IProductsRepository to MySqlProductsRepository:
public class NinjectControllerFactory : DefaultControllerFactory
{
private readonly IKernel _kernel = new StandardKernel(new MyServices());
protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
return null;
return (IController) _kernel.Get(controllerType);
}
public class MyServices: NinjectModule
{
public override void Load()
{
Bind<IProductsRepository>().To<MySqlProductsRepository>();
}
}
}
But I am using NHibernate, and have a separate Session Factory class that has a GetSession() method that returns an ISession.
public static ISessionFactory SessionFactory = CreateSessionFactory();
private static ISessionFactory CreateSessionFactory()
{
var cfg = new Configuration().Configure(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "nhibernate.config"));
cfg.SetProperty(NHibernate.Cfg.Environment.ConnectionStringName, System.Environment.MachineName);
NHibernateProfiler.Initialize();
return cfg.BuildSessionFactory();
}
public static ISession GetSession()
{
return SessionFactory.GetCurrentSession();
}
I wanted to set it up so that my MySqlProductsRepository would be passed and ISession object by Ninject when it was created:
public class MySqlProductsRepository : IProductsRepository
{
private readonly ISession _session;
public MySqlProductsRepository(ISession session)
{
_session = session;
}
And my Controller would be handed a IProductsRepository instance:
public class AdminController : Controller
{
private readonly IProductsRepository _productsRepository;
public AdminController(IProductsRepository productsRepository)
{
_productsRepository = productsRepository;
}
MY PROBLEM:
I can't seem to figure out in my IoC container where I bind my IProductsRepository to my Repository, how to register an ISession, how to hand an ISession to my MyProductsRepository object when it is created, and hand an MyProductsRepository object to my Controller?
I have a couple of blog post I wrote that explain how to use Ninject in and ASP.NET MVC application. The application in the blog post uses the same technologies that you are using: Ninject, NHibernate, and MySql. I also am using a repository pattern. There are a lot of parallels between what you are doing and these posts.
http://blog.bobcravens.com/2010/07/using-nhibernate-in-asp-net-mvc/
http://blog.bobcravens.com/2010/06/the-repository-pattern-with-linq-to-fluent-nhibernate-and-mysql/
http://blog.bobcravens.com/2010/09/the-repository-pattern-part-2/
http://blog.bobcravens.com/2010/11/using-ninject-to-manage-critical-resources/
Take a look. If you have questions, feel free to contact me.