データアクセスレイヤーはどのように構成する必要がありますか?

StackOverflow https://stackoverflow.com/questions/144503

  •  02-07-2019
  •  | 
  •  

質問

最初にs#アーキテクチャの例に従ってシステムを設計しましたこのcodeprojectの記事に記載されている(残念ながら、私はNHibernateを使用していません)。基本的な考え方は、永続化層と通信する必要がある各ドメインオブジェクトに対して、異なるライブラリに対応するデータアクセスオブジェクトがあるということです。各データアクセスオブジェクトはインターフェイスを実装し、ドメインオブジェクトがデータアクセスメソッドにアクセスする必要がある場合、常にインターフェイスに対してコーディングし、DAO自体に対してはコーディングしません。

当時、それでも、この設計は非常に柔軟だと思っていました。ただし、ドメインモデルのオブジェクトの量が増えるにつれて、ここに組織的な問題がないかどうか疑問に思っています。たとえば、ドメイン内のほとんどすべてのオブジェクトは、対応するデータアクセスオブジェクトおよびデータアクセスオブジェクトインターフェイスになります。それだけでなく、これらのそれぞれは異なる場所にあり、いくつかの名前空間の周りのシフトのような単純なことをしたい場合、維持するのがより困難です。

興味深いことに、これらのDAO(および対応するインターフェース)の多くは非常に単純な生き物です-最も一般的なものは、GetById()メソッドを1つだけ持っています。

のようなオブジェクトの束になります
public interface ICustomerDao {
  Customer GetById(int id);
}

public interface IProductDao {
  Product GetById(int id);
}
public interface IAutomaticWeaselDao {
  AutomaticWeasel GetById(int id);
}

実装者が通常非常に簡単な場合。これは、別の方向に進むのが簡単ではないのではないかと思っています。おそらく、単純なデータアクセスタスク用の単一のオブジェクトを使用して戦略を切り替え、もう少し何かを必要とする人のために専用のデータアクセスオブジェクトの作成を予約します複雑。

public interface SimpleObjectRepository {
      Customer GetCustomerById(int id);
      Product GetProductById(int id);
      AutomaticWeasel GetAutomaticWeaselById(int id);
      Transaction GetTransactioinById(int id);
}
public interface TransactionDao {
  Transaction[] GetAllCurrentlyOngoingTransactionsInitiatedByASweatyGuyNamedCarl();
}

このようなアーキテクチャの経験はありますか?全体として、これらの小さなファイルをすべて管理することが唯一の関心事であるため、セットアップに非常に満足しています。しかし、データアクセスレイヤーの構造化に向けて他にどのようなアプローチが存在するのか疑問に思っています。

役に立ちましたか?

解決

単純なシステム以外の単純なアプローチに反対することをお勧めします。通常、各アグリゲートのカスタムリポジトリを作成し、その中にできるだけ適切なロジックをカプセル化する方が良いと思います。

したがって、私のアプローチでは、CustomerRepositoryなど、それを必要とする各アグリゲートのリポジトリを作成します。これには、追加(保存)メソッドがあり、その集約に適している場合は、削除(削除)メソッドがあります。クエリ(GetActive)を含む、適用される他のカスタムメソッドもあり、それらのクエリの一部は仕様を受け入れることができます。

これは多くの努力のように聞こえますが、カスタムクエリ以外のほとんどのコードは、少なくとも最新のORMを使用している場合は実装が非常に簡単なので、継承(ReadWriteRepositoryBase、T:IAggregateRoot)および/または構成(RepositoryHelperクラスの呼び出し)。基本クラスには、GetByIdなど、すべての場合に適用されるメソッドがあります。

これがお役に立てば幸いです。

他のヒント

私はPHPで働いていますが、データアクセスレイヤー用に似たような設定があります。次のようなインターフェイスを実装しました:

interface DataAccessObject
{
public static function get(array $filters = array(), array $order = array(), array $limit = array());
public function insert();
public function update();   
public function delete();
}

そして、各データアクセスオブジェクトは次のように動作します:

class DataAccessObject implements DataAccessObject
{
    public function __construct($dao_id = null) // So you can construct an empty object
    {
        // Some Code that get the values from the database and assigns them as properties
    }
    public static function get(array $filters = array(), array $order = array(), array $limit = array()) {};  // Code to implement function
    public function insert() {};  // Code to implement function
    public function update() {};  // Code to implement function 
    public function delete() {};  // Code to implement function        
}

現在、各データアクセスオブジェクトクラスを手動で構築しているため、データベースにテーブルを追加したり、既存のテーブルを変更したりする場合、明らかに新しいコードを手動で作成する必要があります。私の場合、これはまだコードベースがあった場所からの大きなステップアップです。

ただし、SQLメタデータを使用して(外部キーの制約などを活用する、かなり適切なデータベース設計を持っていると仮定して)これらのデータアクセスオブジェクトを生成することもできます。理論的には、単一の親DataAccessObjectクラスを使用して、クラスのプロパティとメソッドを構築し、データベース内の他のテーブルとの関係を自動的に構築することもできます。これは、DataAccessObjectクラスを拡張して、ある程度の手動で構築されたコードを必要とする状況にカスタムメソッドとプロパティを提供できるため、説明しているものとほぼ同じことを達成します。

.NET開発の補足として、Subsonicなど、データアクセスレイヤーの基本構造を処理するフレームワークを見ましたか?そうでない場合は、 http://subsonicproject.com/ のようなフレームワークを検討することをお勧めします。

またはPHP開発の場合、Zend Frameworkなどのフレームワークが同様の機能を提供します。 http://framework.zend.com

ジョージ私はあなたの気持ちを正確に知っています。 Billyのアーキテクチャは理にかなっていますが、コンテナ、Imapper、およびmapperファイルを作成する必要は苦痛です。次に、NHibernateを使用している場合は、対応する.hbmファイルと通常はいくつかのユニットテストスクリプトを使用して、すべてが機能していることを確認します。

NHibernateを使用していない場合でも、汎用ベースクラスを使用してコンテナをロード/保存することを想定しています。つまり、

public class BaseDAO<T> : IDAO<T> 
{
     public T Save(T entity)
     { 
       //etc......
     }
}
public class YourDAO : BaseDAO<YourEntity>
{
}

NHibernateがなければ、リフレクションまたはその他のメカニズムを使用して、呼び出すSQL / SPROCを決定すると思いますか?

いずれにせよ、これについての私の考えは、DAOが基本クラスで定義された基本的なCRUD操作を実行するだけで、カスタムマッパーとインターフェイスを記述する必要がない場合です。これを達成できると思う唯一の方法は、Reflection.Emitを使用して動的にDAOを動的に作成することです。

また、DAOにリポジトリパターンを使用しており、非常に満足しています。それと。はい、かなりの数の小さなクラスになりますが、それは非常に保守可能です。 IQueriableインターフェイス(LINQ。)を使用すると、もう少し強力になります。データベース構造がかなり一貫している場合は、ジェネリック(T GetById<T>(int id)など)も使用できます。

2番目のアプローチに戻る主な点は、単体テストです。SimpleObjectRepositoryのような大きなファクトリメソッドをモックアウトするには、ICustomerDaoだけをモックアウトするよりも多くの作業が必要です。しかし、私のプロジェクトは、精神的な負荷を軽減し、保守性を高めるため、関連性の高いオブジェクト(ほとんどの単体テストで使用されるオブジェクト)に対する2番目のアプローチを採用しています。

システムをより保守しやすく、理解しやすくしている理由を理解し、実行します。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top