0

私のアプリケーションには、IDataItem を実装する一連の型があります。これらはすべて、データベース行を表す単純な「DTO」型です。インスタンスは、データベースに対して SQL 選択クエリを実行することにより、PetaPoco (マイクロ ORM) を使用して作成されます。SQL 選択クエリは型に固有であり、アプリケーションのバージョン番号にも依存します (型 X にプロパティ Y があるとしますが、アプリ バージョン N の前に対応する列が DB に存在しない場合、クエリはデフォルト値を返します)。 Yについて)。

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

したがって、データアクセスレイヤーで必要なのは、次のメソッドです。

  • 型パラメータ T:IDataItem を持つ
  • T の IEnumerable を返します
  • T に関連付けられた SQL 選択クエリを検索します
  • 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!");
    }

これを達成するためのより良いパターンはありますか?

4

1 に答える 1

1

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 を同時に呼び出すことができます。

于 2016-07-14T07:45:44.280 に答える