1

さまざまなアプリケーション間でコードを共有するために、社内で小さなフレームワークの開発を開始しています。データ アクセスには EF4 を使用しています。カスタム DbContext クラスと汎用リポジトリがあります。

public class RMDbContext : DbContext
{
    // ....
}

public interface IRepository 
{
    IQueryable<T> All();
    void Delete(T entity) where T : class;
    void Add(T entity) where T : class;
    void Update(T entity) where T : class;
    int SaveChanges();
    void RollbackChanges();
}

ここでの問題は、カスタム DbContext クラス (RMDbContext) を使用してリポジトリを実装する方法です。私の同僚は、RMDbContext に IRepository インターフェイスを実装させるのが最善の方法だと考えています。

public class RMDbContext : DbContext, IRepository
{
    // ....
}

正直なところ、コンテキストが特定のコントラクト (IRepository) に関連付けられているため、このアプローチは好きではありません。IMO RMDbContext を使用するリポジトリ実装を作成することをお勧めします。次のようになります。

public class Repository<T> : IRepository where T : RMDbContext, new()
{
    protected readonly RMDbContext context;

    public class Repository()
    {
         context = new T();
    }

    // ....
}

これら2つのアプローチについてどう思いますか?どちらを選びますか。なぜですか。

4

4 に答える 4

4

個人的には、何も作成せず、必要なメソッドがすべて含まれている dbContext を使用することをお勧めします。

私自身が #1 (IRepository の実装) を実装しましたが、正しい ObjectSet または EntitySet を取得して Add/Delete メソッドから追加または削除するために、ファンキーなプログラミングを行うことになります。

オブジェクトモデルに継承階層を追加すると、そのコードはますます複雑になります。

于 2011-11-14T22:13:36.733 に答える
2

まず、リポジトリを RMDbContext と密結合しないでください。これは設計上の悪臭です。常にインターフェイスを使用する必要があります。

次に、IRMDbContext インターフェイスが存在する場合、リポジトリはそれを必要としないため、リポジトリは実装しないでください。実装するのではなく使用する必要があるため、次のようにコンストラクターで IRMDbContext のパラメーターを使用してリポジトリーを作成することをお勧めします。

公開クラス リポジトリ {

protected readonly IRMDbContext context;

public class Repository(IRMDbContext rMDbContext)
{
    this.context = rMDbContext;
}

そして、コンテキストをインスタンス化してリポジトリに送信する Unit of Work クラスについては、次のリンクを参照してください。

EF の作業単位

于 2011-11-15T00:49:40.547 に答える
2

EF リポジトリのベスト プラクティス...
エンティティ フレームワーク - Code First モデル アプローチで、データベース テーブルの POCO エンティティを作成します。
このモデルは、WCF データ コントラクトまたはカスタム属性のいずれかで使用できます。
これは、依存性注入を使用した私の魅力的なオプションです

IRepository インターフェイス

/// <summary>
/// Repository
/// </summary>
public partial interface IRepository<T> where T : BaseEntity
{
    /// <summary>
    /// Returns the queryable entity set for the given type {T}.
    /// </summary>
    IQueryable<T> Table { get; }

    /// <summary>
    /// Creates a new instance of an entity of type {T}
    /// </summary>
    /// <returns>The new entity instance.</returns>
    T Create();

    /// <summary>
    /// Gets an entity by id from the database or the local change tracker.
    /// </summary>
    /// <param name="id">The id of the entity. This can also be a composite key.</param>
    /// <returns>The resolved entity</returns>
    T GetById(object id);

    /// <summary>
    /// Marks the entity instance to be saved to the store.
    /// </summary>
    /// <param name="entity">An entity instance that should be saved to the database.</param>
    /// <remarks>Implementors should delegate this to the current <see cref="IDbContext" /></remarks>
    void Insert(T entity);

    /// <summary>
    /// Marks multiple entities to be saved to the store.
    /// </summary>
    /// <param name="entities">The list of entity instances to be saved to the database</param>
    /// <param name="batchSize">The number of entities to insert before saving to the database (if <see cref="AutoCommitEnabled"/> is true)</param>
    void InsertRange(IEnumerable<T> entities, int batchSize = 100);

    /// <summary>
    /// Marks the changes of an existing entity to be saved to the store.
    /// </summary>
    /// <param name="entity">An instance that should be updated in the database.</param>
    /// <remarks>Implementors should delegate this to the current <see cref="IDbContext" /></remarks>
    void Update(T entity);

    /// <summary>
    /// Marks an existing entity to be deleted from the store.
    /// </summary>
    /// <param name="entity">An entity instance that should be deleted from the database.</param>
    /// <remarks>Implementors should delegate this to the current <see cref="IDbContext" /></remarks>
    void Delete(T entity);


    /// <summary>
    /// Returns the data context associated with the repository.
    /// </summary>
    /// <remarks>
    /// The context is likely shared among multiple repository types.
    /// So committing data or changing configuration also affects other repositories. 
    /// </remarks>
    IDbContext Context { get; }

    /// <summary>
    /// Gets or sets a value indicating whether database write operations
    /// such as insert, delete or update should be committed immediately.
    /// </summary>
    bool AutoCommitEnabled { get; set; }
}

実装

 /// <summary>
/// Entity Framework repository
/// </summary>
public partial class EfRepository<T> : IRepository<T> where T : BaseEntity
{

    #region Fields

    private readonly IDbContext _context;
    private IDbSet<T> _entities;

    #endregion

    #region Ctor

    public EfRepository(IDbContext context)
    {
        this._context = context;
        this.AutoCommitEnabled = true;
    }

    #endregion

    #region interface members

    public virtual IQueryable<T> Table
    {
        get
        {
            return this.Entities;
        }
    }

    public T Create()
    {
        return this.Entities.Create();
    }

    public T GetById(object id)
    {
        return this.Entities.Find(id);
    }

    public void Insert(T entity)
    {
        if (entity == null)
            throw new ArgumentNullException("entity");

        this.Entities.Add(entity);

        if (this.AutoCommitEnabled)
            _context.SaveChanges();
    }

    public void InsertRange(IEnumerable<T> entities, int batchSize = 100)
    {
        try
        {
            if (entities == null)
                throw new ArgumentNullException("entities");

            if (entities.HasItems())
            {
                if (batchSize <= 0)
                {
                    // insert all in one step
                    entities.Each(x => this.Entities.Add(x));
                    if (this.AutoCommitEnabled)
                        _context.SaveChanges();
                }
                else
                {
                    int i = 1;
                    bool saved = false;
                    foreach (var entity in entities)
                    {
                        this.Entities.Add(entity);
                        saved = false;
                        if (i % batchSize == 0)
                        {
                            if (this.AutoCommitEnabled)
                                _context.SaveChanges();
                            i = 0;
                            saved = true;
                        }
                        i++;
                    }

                    if (!saved)
                    {
                        if (this.AutoCommitEnabled)
                            _context.SaveChanges();
                    }
                }
            }
        }
        catch (DbEntityValidationException ex)
        {
            throw ex;
        }
    }

    public void Update(T entity)
    {
        if (entity == null)
            throw new ArgumentNullException("entity");

        if (this.AutoCommitEnabled)
        {
            _context.SaveChanges();
        }
        else
        {
            try
            {
                this.Entities.Attach(entity);
                InternalContext.Entry(entity).State = System.Data.EntityState.Modified;
            }
            finally { }
        }
    }

    public void Delete(T entity)
    {
        if (entity == null)
            throw new ArgumentNullException("entity");

        if (InternalContext.Entry(entity).State == System.Data.EntityState.Detached)
        {
            this.Entities.Attach(entity);
        }

        this.Entities.Remove(entity);

        if (this.AutoCommitEnabled)
            _context.SaveChanges();
    }


    public IDbContext Context
    {
        get { return _context; }
    }

    public bool AutoCommitEnabled { get; set; }

    #endregion

    #region Helpers

    protected internal ObjectContextBase InternalContext
    {
        get { return _context as ObjectContextBase; }
    }

    private DbSet<T> Entities
    {
        get
        {
            if (_entities == null)
            {
                _entities = _context.Set<T>();
            }
            return _entities as DbSet<T>;
        }
    }

    #endregion

}

これを使用して、将来的に別のリポジトリと実装を追加できます。これは、既存のデータには影響しません。それを試してみてください.....

于 2014-05-02T06:57:33.673 に答える