如何将IDbContext传递给DbMigrationsConfiguration

时间:2013-02-22 18:43:37

标签: entity-framework entity-framework-5 code-first dbcontext

已经从许多资源中使用EF5 Code First实现了通用存储库,工作单元模式,并提出了以下程序集。

接口,上下文,模型,存储库,UnitsOfWork

在Context程序集中,我有我的迁移文件夹,其中包含Configuration.cs

internal sealed class Configuration : DbMigrationsConfiguration<Context.SportsContext>
{
    public Configuration()
    {
        AutomaticMigrationsEnabled = true;
    }

    protected override void Seed(Context.SportsContext context)
    {
        //  This method will be called after migrating to the latest version.

        //  You can use the DbSet<T>.AddOrUpdate() helper extension method 
        //  to avoid creating duplicate seed data. E.g.
        //
        //    context.People.AddOrUpdate(
        //      p => p.FullName,
        //      new Person { FullName = "Andrew Peters" },
        //      new Person { FullName = "Brice Lambson" },
        //      new Person { FullName = "Rowan Miller" }
        //    );
        //
    }
}

正如您所看到的,DbMigrationsConfiguration接收我的SportsContext,它也在上下文程序集(Contexts文件夹)中定义

 public class SportsContext : IDbContext
{
    private readonly DbContext _context;

    public SportsContext()
    {
        _context = new DbContext("SportsContext");

    }

    public void Dispose()
    {
        _context.Dispose();
    }

    public IDbSet<T> GetEntitySet<T>() where T : class
    {
        return _context.Set<T>();
    }

    public void ChangeState<T>(T entity, EntityState state) where T : class
    {
        _context.Entry(entity).State = state;
    }

    public void SaveChanges()
    {
        _context.SaveChanges();
    }
}

这实现了在Interfaces程序集

中定义的IDbContext
public interface IDbContext : IDisposable
{
    IDbSet<T> GetEntitySet<T>() where T : class;
    void ChangeState<T>(T entity, EntityState state) where T : class;
    void SaveChanges();
}

在我的UnitsOfWork程序集中,我有以下类

public class SportUnitOfWork : IUnitofWork
{
    private readonly IDbContext _context;

    public SportUnitOfWork()
    {
        _context = new SportsContext();
    }

    private GenericRepository<Team> _teamRepository;
    private GenericRepository<Fixture> _fixtureRepository;

    public GenericRepository<Team> TeamRepository
    {
        get { return _teamRepository ?? (_teamRepository = new GenericRepository<Team>(_context)); }
    }

    public GenericRepository<Fixture> FixtureRepository
    {
        get { return _fixtureRepository ?? (_fixtureRepository = new GenericRepository<Fixture>(_context)); }
    }

    public void Save()
    {
        _context.SaveChanges();
    }

    public IDbContext Context
    {
        get { return _context; }
    }

    private bool _disposed;

    protected virtual void Dispose(bool disposing)
    {
        if (!_disposed)
        {
            if (disposing)
            {
                _context.Dispose();
            }
        }
        _disposed = true;
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

}

例如,我在存储库程序集中添加了GenericRepository类

public class GenericRepository<T> : IGenericRepository<T> where T : class
{
    private IDbContext _context;

    public GenericRepository(IDbContext context)
    {
        _context = context;
    }

    public GenericRepository(IUnitofWork uow)
    {
        _context = uow.Context;
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (!disposing) return;

        if (_context == null) return;
        _context.Dispose();
        _context = null;
    }

    public void Add(T entity)
    {
        _context.GetEntitySet<T>().Add(entity);
    }

    public void Update(T entity)
    {
        _context.ChangeState(entity, EntityState.Modified);
    }

    public void Remove(T entity)
    {
        _context.ChangeState(entity, EntityState.Deleted);
    }

    public T FindSingle(Expression<Func<T, bool>> predicate = null, params Expression<Func<T, object>>[] includes)
    {
        var set = FindIncluding(includes);
        return (predicate == null) ? set.FirstOrDefault() : set.FirstOrDefault(predicate);
    }

    public IQueryable<T> Find(Expression<Func<T, bool>> predicate = null, params Expression<Func<T, object>>[] includes)
    {
        var set = FindIncluding(includes);
        return (predicate == null) ? set : set.Where(predicate);
    }

    public IQueryable<T> FindIncluding(params Expression<Func<T, object>>[] includeProperties)
    {
        var set = _context.GetEntitySet<T>();

        if (includeProperties != null)
        {
            foreach (var include in includeProperties)
            {
                set.Include(include);
            }
        }

        return set.AsQueryable();
    }

    public int Count(Expression<Func<T, bool>> predicate = null)
    {
        var set = _context.GetEntitySet<T>();
        return (predicate == null) ? set.Count() : set.Count(predicate);
    }

    public bool Exist(Expression<Func<T, bool>> predicate = null)
    {
        var set = _context.GetEntitySet<T>();
        return (predicate == null) ? set.Any() : set.Any(predicate);
    }
}

我遇到的问题是继承自DbMigrationsConfiguration的Configuration类需要一个DbContext参数。

错误是错误1类型'Contexts.Context.SportsContext'不能在泛型类型或方法'System.Data.Entity.Migrations.DbMigrationsConfiguration'中用作类型参数'TContext'。从'Contexts.Context.SportsContext'到'System.Data.Entity.DbContext'没有隐式引用转换。

我可以将SportsContext更改为也继承自DbContext但是我需要在UnitsOfWork程序集中添加对EntityFramework 5的引用,因为我们希望可能更改或取出每个层而不引用底层模型这就是为什么我去了用这种模式。

由于我们正在考虑在未来添加更多的上下文和模型,因此我们希望设置一个架构,我们可以添加上下文,模型,然后在需要时实现相关的接口。

如果我已正确理解模式,WebAPI Restful Web服务将通过SportUnitOfWork与我们的数据进行交互。

如果有人对我如何做到这一点或任何我做错的想法请告诉我

提前感谢马克

1 个答案:

答案 0 :(得分:1)

通过执行以下操作解决此问题

将我的SportsContext类更改为抽象的

BaseContext
public abstract class BaseContext : IDbContext
{
    protected DbContext Context;

    public void Dispose()
    {
        Context.Dispose();
    }

    public IDbSet<T> GetEntitySet<T>() where T : class
    {
        return Context.Set<T>();
    }

    public void Add<T>(T entity) where T : class
    {
        DbEntityEntry dbEntityEntry = GetDbEntityEntrySafely(entity);
        dbEntityEntry.State = EntityState.Added;
    }

    public void Update<T>(T entity) where T : class
    {
        DbEntityEntry dbEntityEntry = GetDbEntityEntrySafely(entity);
        dbEntityEntry.State = EntityState.Modified;
    }

    public void Delete<T>(T entity) where T : class
    {
        DbEntityEntry dbEntityEntry = GetDbEntityEntrySafely(entity);
        dbEntityEntry.State = EntityState.Deleted;
    }

    public void SaveChanges()
    {
        // At the moment we are conforming to server wins when handling concurrency issues
        // http://msdn.microsoft.com/en-us/data/jj592904

        try
        {
            Context.SaveChanges();
        }
        catch (DbUpdateConcurrencyException e)
        {
            //Refresh using ServerWins
            var objcontext = ((IObjectContextAdapter) Context).ObjectContext;
            var entry = e.Entries;

            objcontext.Refresh(RefreshMode.StoreWins, entry);

            SaveChanges();
        }
    }

    private DbEntityEntry GetDbEntityEntrySafely<T>(T entity) where T : class
    {
        DbEntityEntry dbEntityEntry = Context.Entry(entity);

        if (dbEntityEntry.State == EntityState.Detached)
        {
            // Set Entity Key
            var objcontext = ((IObjectContextAdapter) Context).ObjectContext;

            if (objcontext.TryGetObjectByKey(dbEntityEntry.Entity))

            Context.Set<T>().Attach(entity);
        }

        return dbEntityEntry;
    }
}

在Context文件夹中创建一个名为FootballContext的新类,它继承自BaseContext。

public class FootballContext : BaseContext
{
    public FootballContext(string connectionstringName)
    {
        Context = new BaseFootballContext(connectionstringName);

    }
}

创建了一个名为DbContexts的新文件夹

在这里创建了以下类,

public class BaseFootballContext : DbContext
{
    public BaseFootballContext(string nameOrConnectionString) : base(nameOrConnectionString)
    {
    }

    public IDbSet<Fixture> Fixtures { get; set; }
    public IDbSet<Team> Teams { get; set; }  
}

public class MigrationsContextFactory : IDbContextFactory<BaseFootballContext>
{
    public BaseFootballContext Create()
    {
        return new BaseFootballContext("FootballContext");
    }
}

现在我的Configuration类可以接受BaseFootballContext,因为这是一个DbContext。

我的UnitOfWork类现在可以将上下文设置为FootballContext,因此不必引用EntityFramework。

这也适用于迁移。

我现在唯一的问题是弄清楚如何让它在断开连接的环境中工作,因为我在重新连接实体和应用更新时遇到问题。