6

私は中途採用の哲学的建築危機を経験しています。クライアントコード(UI、Webサービス、MVC、MVPなど)と見なされるものとサービスレイヤーの間に非常に明確な線があります。ただし、サービスレイヤーからの線は、1分ごとにぼやけてきています。そして、それはすべて、Linqを使用してコードをクエリする機能と遅延読み込みの概念から始まりました。

コントラクトと実装で構成されるビジネスレイヤーを作成しました。その場合、実装は他のコントラクトなどに依存する可能性があります。これは、DIを備えたIoCコンテナを介して処理されます。DataAccessを処理するサービスが1つあり、それが行うのはUnitOfWorkを返すことだけです。このUnitOfWorkは、拡張時にトランザクションを作成し、Commitメソッドでデータをコミットします。[この記事を見る(Testability and Entity Framework 4.0) ]:

public interface IUnitOfWork : IDisposable {
   IRepository<T> GetRepository<T>() where T : class;
   void Commit();
}

リポジトリは汎用であり、2つの実装(EF4とInMemoryデータストア)に対して機能します。Tは、データベーススキーマまたはEF4マッピングから生成されるPOCOで構成されます。テスト容易性はリポジトリ設計に組み込まれています。インメモリ実装を活用して、期待どおりの結果を表明できます。

public interface IRepository<T> where T : class {
   IQueryable<T> Table { get; }
   void Add(T entity);
   void Remove(T entity);
}

データソースは抽象化されていますが、IQueryableを使用すると、ビジネスロジック内の任意の場所にクエリを作成できます。これが例です。

public interface IFoo {
   Bar[] GetAll();
}

public class FooImpl : IFoo {
   IDataAccess _dataAccess;
   public FooImpl(IDataAccess dataAccess) {
      _dataAccess = dataAccess;
   }

   public Bar[] GetAll() {
      Bar[] output;
      using (var work = _dataAccess.DoWork()) {
          output = work.GetRepository<Bar>().Table.ToArray();
      }
      return output;
   }
}

これで、複雑なフィルターを使用して結合を実行すると、クエリがさらに複雑になる可能性があることがわかります。

したがって、私の質問は次のとおりです。

  1. BLLとDALの間に明確な区別がないことは重要ですか?
  2. InMemory抽象化のように機能するリポジトリ層の背後にある場合、クエリ可能性はデータアクセスまたはビジネスロジックと見なされますか?

追加:考えれば考えるほど、2番目の質問だけが尋ねられるべきだったのかもしれません。

4

3 に答える 3

6

あなたの質問に答える最良の方法は、少し前に戻って、ビジネスロジック層とデータアクセス層を分離することが推奨される方法である理由を検討することだと思います。

私の考えでは、理由は単純です。ビジネスロジックは価値のある場所であり、データ層とビジネスロジックは時間の経過とともにほぼ独立して変化する必要があるため、ビジネスロジックをデータ層から分離してください。ビジネスロジックは、すべてのデータアクセス層が何をするかについての詳細な知識がなくても読み取り可能である必要があります。

したがって、クエリ体操のリトマス試験は次のように要約されます。

  1. ビジネスロジックの大部分を混乱させることなく、システムのデータスキーマに変更を加えることができますか?
  2. あなたのビジネスロジックはあなたと他のC#開発者に読めますか?
于 2010-09-28T23:50:11.770 に答える
1

1.物事を成し遂げることよりも哲学に関心がある場合のみ。:)

2.間に抽象化があるので、それはビジネスロジックだと思います。そのリポジトリレイヤーをDALの一部と呼び、それを使用するものはすべてBLと呼びます。

しかし、ええ、これは私にもぼやけています。しかし、それは重要ではないと思います。このようなパターンを使用するポイントは、同時に通信しやすいクリーンで使用可能なコードを作成することであり、その目標はどちらの方法でも達成されます。

于 2010-09-28T23:45:47.617 に答える
1

1.BLLとDALの間に明確な区別がないことは重要ですか?

それは確かに重要です!Tableプロパティを使用するプログラマーは、その影響(データベースのラウンドトリップ、クエリの変換、オブジェクトの追跡)を理解する必要があります。これは、ビジネスロジッククラスを読むプログラマーにも当てはまります。

2. InMemory抽象化のように機能するリポジトリ層の背後にある場合、クエリ可能性はデータアクセスまたはビジネスロジックと見なされますか?

抽象化は、問題を隠すための包括的なものです。

抽象化が完全である場合、クエリはメモリ内のコレクションに対して動作していると抽象的に見なされる可能性があるため、データアクセスではありません。

ただし、抽象化はリークします。データの世界で意味のあるクエリが必要な場合は、抽象化を超えて機能するように努力する必要があります。その余分な努力(抽象化を打ち負かす)は、データアクセスコードを生成します。


いくつかの例:

output = work.GetRepository<Bar>().Table.ToArray(); 

これはコードが(抽象的に)問題ないということです。しかし、データの世界では、テーブル全体をスキャンすることになり、(少なくとも一般的には)ばかげています!


badquery = work.GetRepository<Customer>().Table.Where(c => c.Name.Contains("Bob")).ToArray(); 
goodquery = work.GetRepository<Customer>().Table.Where(c => c.Name.StartsWith("Bob")).ToArray(); 

にインデックスがある場合、Goodqueryはbadqueryよりも優れていますCustomer.Name。しかし、抽象化を解除しない限り、その事実は私たちには利用できません。


badquery = work.GetRepository<Customer>().Table
  .GroupBy(c => c.Orders.Count())
  .Select(g => new
  {
    TheCount = g.Key,
    TheCustomers = g.ToList()
  }).ToArray();
goodquery = work.GetRepository<Customer>().Table
  .Select(c => new {Customer = c, theCount = c.Orders.Count())
  .ToArray()
  .GroupBy(x => x.theCount)
  .Select(g => new
  {
    TheCount = g.Key,
    TheCustomers = g.Select(x => x.Customer).ToList()
  })
  .ToArray();

badqueryは、グループごとにグループキーでデータベースを再クエリするため、goodqueryはbad queryよりも優れています(さらに悪いことに、顧客のフィルタリングに役立つインデックスが存在する可能性はほとんどありませんc.Orders.Count())。


テスト容易性はリポジトリ設計に組み込まれています。InMemoryの実装を活用して、期待どおりの結果を表明できます。

クエリをメモリ内のコレクションに対して実際に実行する場合は、クエリがテストされているという幻想を抱かないでください。これらのクエリは、データベースが関与していない限りテストできません。

于 2010-09-29T03:50:04.840 に答える