2016-07-14 3 views
0

私のアプリケーションにはIDataItemを実装するタイプのセットがあります。それらはすべてデータベース行を表す単純な「DTO」型です。インスタンスは、データベースに対してSQL selectクエリを実行することによってPetaPoco(マイクロORM)を使用して作成されます。 SQLのselectクエリは型に固有であり、アプリケーションのバージョン番号にも依存します(X型にはYというプロパティがありますが、アプリケーションのバージョンNより前にはDBには対応する列がありません - この場合、 Yについて)。IDataItemを実装する各タイプには関連する文字列(SQL select qry)が必要ですが、インスタンス化する前にアクセスする必要があります

アプリケーションの性質上、これらのタイプが多く、将来的にはその数が増加するということです。私はデータアクセス層でジェネリックスを使用してコードの量を最小限に抑え、(ii)タイプを設計する際に将来の開発者に必要なSQLクエリを設計させようとしています。

  • は型パラメータTを持っています:IDataItem
  • はT
  • のIEnumerableをを返し
  • は、関連付けられたSQL SELECTクエリを見つける方法が何であるかを私はしたいデータアクセス層でそう

    、 T

  • PetaPocoを使用してDBに対してクエリを実行し、T のリストを作成します(それより少し複雑です - 動的なwhere句もありますが、単純なままにしておきます)

私の挑戦は、Tのインスタンスが作成される前に型パラメータTのSQLクエリを取得する方法です。理想的にはIDataItemにメソッドを追加します。 string SqlSelectFrom(int appVersion)しかし、それを呼び出すためにインスタンスが必要です(インターフェイスに静的メンバーが必要な場合のみ!)。私が今持っている最高のは、このようなデータアクセス層の内部関数である(しかし、これは実際にSQLクエリを実行するために、将来のタイプの開発者を強制的に私の要件を満たしていない):

private string GetSqlSelectFrom<T>(int appVersion) where T : IDataItem 
    { 
     if (typeof(T) == typeof(ProductDto)) 
      return "select ProductId, ProductCode from Product"; 

     if (typeof(T) == typeof(ColourDto)) 
      return "select ColourId, ColourCode from Colour"; 

     etc 

     throw new Exception("No SQL defined!"); 
    } 

が良くありますこれを達成するためのパターン?

+0

は、私は2つの方法を考えることができます。 は、(1)(2)アプリのバージョンと異なる場合がありクエリとして機能しない属性 –

+0

DTOタイプのレジストリの種類を使用してDTOクラス 上の属性を使用して。レジストリplzの詳細を説明しますか? – Laurence

答えて

1

一つの方法は、DTOタイプのため、レジストリの種類を使用している:

public static class DtoRegistry 
{ 
    private static readonly Dictionary<Tuple<Type, int>, string> _sqlSelectByType = 
     new Dictionary<Tuple<Type, int>, string>(); 

    public static void RegisterDto<T>(int appVersion, string sqlSelect) where T : IDataItem 
    { 
     var key = new Tuple<Type, int>(typeof(T), appVersion); 
     _sqlSelectByType[key] = sqlSelect; 
    } 

    public static string GetSqlSelectFrom<T>(int appVersion) where T : IDataItem 
    { 
     var key = new Tuple<Type, int>(typeof(T), appVersion); 
     return _sqlSelectByType[key]; 
    } 
} 

とどこかのアプリケーションのスタートアップコードで、すべてのDTOの種類が登録されている必要があります

DtoRegistry.RegisterDto<ProductDto>(appVersion: 1, sqlSelect: "SELECT * FROM Products"); 
DtoRegistry.RegisterDto<ProductDto>(appVersion: 2, sqlSelect: "SELECT * FROM ProductsV2"); 

DtoRegistry.RegisterDto<ColourDto>(appVersion: 1, sqlSelect: "SELECT * FROM Colours"); 
DtoRegistry.RegisterDto<ColourDto>(appVersion: 2, sqlSelect: "SELECT * FROM ColoursV2"); 

レジストリを持つ1つの警告スレッドセーフです。私は、アプリケーションの初期化をシングルスレッドで実行し、レジストリを満たし、初期化が完了するとレジストリに変更を許可しません。その後、アプリケーションの実行中に、複数のスレッドが安全にGetSqlSelectFromを同時に呼び出すことができます。

+0

有望ですが、SQLクエリは定数ではありません。それはアプリのバージョンの関数です。 – Laurence

+0

ああ、大丈夫です。私は答えを修正しています。 –

+0

完了 - appVersion –

関連する問題