2

多くのリソースから EF5 Code First を使用して Generic Repository、Unit of Work パターンを実装しており、次のアセンブリを作成しました。

インターフェイス、コンテキスト、モデル、リポジトリ、UnitsOfWork

Context アセンブリには、Configuration.cs を含む migrations フォルダーがあります。

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 は、コンテキスト アセンブリ (Contexts フォルダー) でも定義されている SportsContext を取り込みます。

 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);
    }

}

例として、Repositories アセンブリに 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 を介してデータと対話します。

どうすればこれを行うことができるか、または私が間違っていることについて誰かがアイデアを持っている場合は、私に知らせてください

前もって感謝します マーク

4

1 に答える 1

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フォルダーに、BaseContextから継承するFootballContextという新しいクラスを作成しました。

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");
    }
}

これで、これはDbContextであるため、ConfigurationクラスはBaseFootballContextを取り込むことができます。

UnitOfWorkクラスでコンテキストをFootballContextに設定できるようになったため、EntityFrameworkを参照する必要はありません。

これは移行でも機能します。

私が今抱えている唯一の問題は、エンティティの再接続と更新の適用に問題があるため、これを切断された環境で機能させる方法を理解することです。

于 2013-03-04T10:52:18.897 に答える