I'm writing a program at the moment that utilizes StructureMap as an IOC container.
I've implemented a couple of interfaces - IUnitOfWork
and IDataAccessRepository
that are resolved at run time with the the following classes (which are in their own project - CardGame.EntityFrameworkProvider
).
EntityFrameworkRepository.cs
public class EntityFrameworkRepository<T> : IDataAccessRepository<T>
where T : class
{
private DbContext _ctx;
private DbSet<T> set;
internal EntityFrameworkRepository(DbContext ctx)
{
_ctx = ctx;
set = _ctx.Set<T>();
}
public IEnumerable<T> Elements
{
get { return set; }
}
public T Get(int id)
{
return set.Find(id);
}
public void Add(T t)
{
set.Add(t);
}
public void Update(T t)
{
set.Attach(t);
_ctx.Entry<T>(t).State = EntityState.Modified;
}
public void Delete(T t)
{
if (_ctx.Entry<T>(t).State == EntityState.Detached)
set.Attach(t);
set.Remove(t);
}
}
EntityFrameworkUnitofWork.cs
public class EntityFrameworkUnitOfWork : DbContext, IUnitOfWork
{
/// <summary>
/// Creates an EntityFrameworkUnitOfWork.
/// </summary>
/// <param name="connectionStringOrName"></param>
public EntityFrameworkUnitOfWork(string connectionStringOrName) : base(connectionStringOrName)
{
Database.SetInitializer<EntityFrameworkUnitOfWork>(new DropCreateDatabaseIfModelChanges<EntityFrameworkUnitOfWork>());
Creatures = new EntityFrameworkRepository<Models.Cards.Creature>(this);
MagicCards = new EntityFrameworkRepository<Models.Cards.Magic>(this);
EffectDescriptors = new EntityFrameworkRepository<Models.Effects.EffectDescriptor>(this);
}
#region Repositories
public IDataAccessRepository<Models.Cards.Creature> Creatures
{
get;
private set;
}
public IDataAccessRepository<Models.Cards.Magic> MagicCards
{
get;
private set;
}
public IDataAccessRepository<Models.Effects.EffectDescriptor> EffectDescriptors
{
get;
private set;
}
#endregion
public new void SaveChanges()
{
base.SaveChanges();
}
}
Finally, in my main method - in another project - I bind the dependencies together using StructureMap. Main
ObjectFactory.Configure(x =>
{
x.Scan(scan =>
{
scan.LookForRegistries();
scan.Assembly("CardGame.DataAccess");
scan.Assembly("CardGame.EntityFrameworkProvider");
});
#region Persistence
x.For<CardGame.DataAccess.IUnitOfWork>().Use(new CardGame.EntityFrameworkProvider.EntityFrameworkUnitOfWork("MyConnectionString"));
#endregion
});
My issue is, is that with the EntityFrameworkUnitOfWork
extending DbContext
, my CardGame.Server
(project containing Main.cs) is unable to compile because it doesn't (intentionally) contain a reference to EntityFramework. I'm trying to make this as database-agnostic as possible, and so far it has gone well, but the moment I made EntityFrameworkUnitOfWork
extend DbContext
(so I could apply a DropCreateDatabaseIfNotExists
initializer), the whole thing went bang.
The reason I am making EntityFrameworkUnitOfWork
extend DbContext
is mainly because IUnitOfWork
contains all the repositories that EntityFrameworkUnitOfWork
(or other providers) need to implement. I initially didn't do this, but I reasoned that I am removing DAL from the models, rather than models from the DAL - and it would be so much easier to have properties on the IUnitOfWork
object to grab the repositories I needed.
Have you any recommendations?
Adding a reference to EntityFramework does fix the problem, but that also means I have to add a reference to EntityFramework to my main project when it doesn't use it at all!
EDIT: Update! I managed to get it working, but ONLY by adding an EntityFramework reference to my project. I created a new class called EntityFrameworkContext
with DbSet<T>
in them, and that is created when an EntityFrameworkUnitOfWork
is created (which has an initializer in it's static constructor). I guess this question boils down to:
Assume project with EF layer is Project A. Project having layer injected into it is Project B.
How can I have EntityFramework settings on Project A (presumably in it's App.config) so that Project B doesn't need a reference to EntityFramework in it's configuration? The whole idea is that the layer should be swappable with some other project (let's say NHibernate or ActiveRecord), and I shouldn't need to modify my main project to occupy those modifications. Furthermore, project A does not directly reference EntityFramework at all - it makes no sense for it to have a reference to it.
If the problem is this line
then you should probably think about using a registry. This way you can have a registry in your project referencing EntityFramework that looks something like this:
Since your ObjectFactory is already configured to look for registries, this should be enough to get it working.