Domanda

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.

È stato utile?

Soluzione

If the problem is this line

x.For<CardGame.DataAccess.IUnitOfWork>().Use(new CardGame.EntityFrameworkProvider.EntityFrameworkUnitOfWork("MyConnectionString"));

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:

public class MyProjectRegistry : Registry
{
    public MyProjectRegistry()
    {
        For<CardGame.DataAccess.IUnitOfWork>().Use(new CardGame.EntityFrameworkProvider.EntityFrameworkUnitOfWork("MyConnectionString"));
    }
}

Since your ObjectFactory is already configured to look for registries, this should be enough to get it working.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top