2

ORM/DAL として EF (5.0 Beta Code First) を使用する場合の新しいプロジェクトのベスト プラクティスを調査しています。重要な考慮事項は、テスト容易性、疎結合設計、リポジトリ全体の作業単位/トランザクション サポートです。

EF 内では DbContext は UoW であり、DbSet はリポジトリであり、サービス レイヤーでは、DbContexts SaveChanges() メソッドによって調整された複数のリポジトリ間で変更を加えることができることを理解しています。これが私のサンプル構成です:

public interface IMyContext
{
    IDbSet<Foo> Foos{ get; }

    IDbSet<Bar> Bars { get; }

    int SaveChanges();

    void Dispose();
}

public class EFMyContext : DbContext, IMyContext
{
    private IDbSet<Foo> _foos;
    private IDbSet<Bar> _bars;

    public EFMyContext()
        : base("name=MyConnectionString")
    {
        Database.SetInitializer<EFMyContext>(null);
    }

    public IDbSet<Foo> Foos
    {
        get
        {
            if (_foos == null)
            {
                _foos = this.Set<Foo>();
            }

            return _foos;
        }
    }

    public IDbSet<Bar> Bars
    {
        get
        {
            if (_bars == null)
            {
                _bars = this.Set<Bar>();
            }

            return _bars;
        }
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Configurations.Add(new FooConfiguration());
        modelBuilder.Configurations.Add(new BarConfiguration());

        base.OnModelCreating(modelBuilder);
    }

これまでのところすべて順調です。これを使いたい場合は、このような上位層です

public class MyService : IMyService
{
    private IMyContext _context;

    public MyService(IMyContext context)
    {
        _context = context;
    }

    public void DoSomethingWithMyContext()
    {
        // fancy implementation code
    }
}

MyContext は IDBSet 型のプロパティを公開するため、EntityFramework.dll に直接依存しているため、ここで問題が発生します。これは正しくないようで、この質問に非常に似ています。

私の質問は、EF への直接的な依存関係を抽象化する方法ですか? ライブ コンテキストを渡すために独自のリポジトリと作業単位を導入することを考えましたが、これは変更追跡や他のすべての優れた EF 機能にどのような影響を与えるでしょうか?

私が注目しているのは、コンテキストのライフサイクルを管理するための IoC メカニズムです。その時点で UoW を廃止することはできますか?

あいまいで申し訳ありませんが、私はこれで研究が飽和状態にあり、実装の前に開始する決定的な場所が必要です.

4

3 に答える 3

2

自問してみてください: 私のアーキテクチャは何を解決すべきでしょうか? サービス アセンブリから EntityFramework.dll を参照することが間違っている理由を明確に答えられない限り、時間を無駄にしていることになります。

実際、EntityFramework.dll を参照することに問題はありません。なぜそれが必要なのですか?サービスは EF に関連するものを公開しないため、完全にモック可能です。サービス コードの単体テストも行う場合は、サービスが EF で抽象化された方法で動作することを確認する必要があります。そのような場合、リポジトリは道のりになる可能性がありますが、それは非常に専門的なリポジトリになります-通常提案される一般的なナンセンスではありません. リポジトリは EF に関連するすべてを隠し、サービスはアプリケーションに EF のようなものが存在することを認識しません。また、EF 機能に関する質問にも答えます。サービスをテスト可能にしたい場合、サービスはこれらの機能から完全に独立している必要があります。たとえば、サービス コードを LINQ-to-Entities または遅延読み込みに依存させるべきではありません。原因になるだけテスト中のトラブル

リポジトリを実装しても、リポジトリがサービスと同じアセンブリにあり、そのアセンブリが EntityFramework.dll を参照している場合は問題ありません。

于 2012-04-26T13:43:20.437 に答える
1

サービスレイヤーでは、実際にを使用する必要はありませんIQueryable<T>

このようにして、 LINQをサポートするORMと緊密に結合されるためです。すべてのLINQクエリは、具象DAL内にカプセル化する必要があります。

サービスレイヤーでDALに依存しないリポジトリを定義する方がよいでしょう。

public interface IRepository<T>
{
    T GetById(int id);
    IEnumerable<T> GetAll();

    // Filter is some DTO that will be mapped to 
    // concrete LINQ query inside your DAL
    IEnumerable<T> GetFiltered(Filter<T> filter);

    void Add(T item);
    void Update(T item);
    void Remove(T item);
}

更新: LINQが好きな場合は、ObjectContextとObjectSetの独自のインターフェイスを定義できます。

public interface IObjectContext : IUnitOfWork
{
    IObjectSet<T> Set<T>() where T : class;
}

public interface IObjectSet<T> : IObjectQuery<T>
    where T : class
{
    void Remove(T entity);
    void Add(T entity);
}

public interface IObjectQuery<out T> : IQueryable<T>, IQueryableWrapper
     where T : class
{
    IObjectQuery<T> Include(string path);
}

次に、EF用のアダプターを作成できます。また、EFは式ツリーのインターフェイスを理解できないため、アダプタにクエリ変換レイヤーを追加する必要があります。これがQueryTranslatorの例です:https ://stackoverflow.com/a/1846030/1275399

于 2012-04-26T13:51:15.240 に答える
0

IMyContext に DbSet プロパティを持たず、実装にのみ dbset を持つことができます。IMyContext は、コンテキストの保存 (および破棄) について知るためにのみ使用する必要があり、それ以外には何も使用しないでください。したがって、リポジトリ内では、sql と対話する方法を知っている戦略を持つことができます。たとえば、ef を使用して、その dbsets 部分を処理させることができます。これを行う必要があるのは、将来的に EF を移動して別のものに置き換える計画がある場合のみです。

このアプローチの詳細については、こちらをご覧ください

于 2014-12-01T11:03:39.910 に答える