1

私はC#でデータアクセスを実験しています。Save(object o)オブジェクトの各プロパティを循環し、属性を使用してそれらをデータベースと照合するメソッドを持つクラスを作成しています。

私の問題は、クラスが接続文字列を取得する必要があることですが、ユーザーにそれを提供してもらいたいのです。基本的に、設定ファイルに限定したくありません。これまで私が考えたことは次のとおりです。

  • ユーザーがカスタムクラスを介して文字列を提供する各接続の前にイベントを発生させる(イベントを介しEventArgsて独自のオブジェクトインスタンスをASP.NETに提供する方法と同様)ObjectDataSourceObjectCreating
  • データアクセスクラスのプロパティ
  • 両方の組み合わせ。イベントにサブスクライバーがない場合は、プロパティの値と一致します。

他にどのような可能性があり、このシナリオで最善の戦略は何でしょうか?

4

2 に答える 2

2

正確に 1 人のサブスクライバーが存在しない場合、コードが壊れてしまうため、イベントは自然ではありません。イベントは、サブスクライバーの数がイベントを発生させるクラスにとって問題にならないユースケースを対象としています。

プロパティまたはインターフェイス ( などIConnectionProvider) を使用して、接続文字列を挿入します。インターフェイス バージョンは、DI コンテナーでの使用に適しています。

于 2012-12-28T20:15:16.787 に答える
1

usr にある程度同意すると、どちらの方法でも IConnectionProvider を作成する必要があります。

ただし、それは、開発者にクラスの柔軟性をどの程度許可したいかによると思います。

クラスの各インスタンスに、同じ状態を保ち、データベースにアクセスする必要があるすべてのメソッド呼び出しに使用されるグローバル接続を強制しますか? その場合、クラスはコンストラクターで IConnectionProvider を受け取る必要があります。

クラスの状態が変化したときに開発者に警告し、接続を変更する柔軟性を提供しますか? もしそうなら、イベントを提供するのが良い選択肢かもしれません。

あなたのクラスは静的ですか、それとも開発者にメソッド呼び出しで別の接続を提供するように強制したいですか? 次に、各メソッドは IConnectionProvider を受け取る必要があります。

クラスでどの程度の柔軟性を許可するかを決定し、それに基づいて選択する必要があります。

極端な柔軟性とカスタマイズを許可したい場合は、ラムダ式を検討することをお勧めします。それらを使用すると、コードの特定のポイントで呼び出すメソッドを開発者が提供できるようになります。ラムダ式を使用して、呼び出し元が IDataReader を読み取るためのコードを提供するだけでよい一般的なデータベース メソッドを作成することで、コードを統合することができました。IDataReader は、それらのためにセットアップし、例外をキャッチし、必要なデータベース オブジェクトを閉じて破棄します。 .

編集:これは、接続コードを統合するために行ったことの例です。

    public static T ExecuteReader<T>(IDbConnection connection, string commandText, Func<IDataReader, T> readData) where T : class
    {
        IDbCommand command = connection.CreateCommand();
        command.CommandText = commandText;

        try
        {
            connection.Open();
            IDataReader reader = command.ExecuteReader();
            T returnValue = readData(reader); //Call the code provided by the caller and get the return object.

            reader.Close();
            reader.Dispose();

            return returnValue; //Return their return object.
        }
        finally
        {
            if (command != null)
            {
                command.Dispose();
            }
            if (connection != null)
            {
                try
                {
                    if (connection.State != ConnectionState.Closed)
                    {
                        connection.Close();
                    }
                }
                finally
                {
                    connection.Dispose();
                }
            }
        }
    }

使用例:

MyDataList.AddRange(
    Database.ExecuteReader<List<MyDataModel>>( //Tell ExecuteReader what type of object to return
    connection, //Pass in the connection
    commandString, //Pass in the command
    delegate(IDataReader reader) //This code is called from inside the ExecuteReader method.
    {
        List<MyDataModel> List = new List<MyDataModel>();
        while (reader.Read())
        {
            //Read each record, transform it into MyDataModel, then add it to the List.
        }
        return List;
    }
}));

汎用の ExecuteReader メソッドが作成されたのは、コマンドを作成し、接続を開き、そのすべてを破棄するためのコードが同じままで、すべてのオブジェクトに対して複製されるためです。これにより、不要なコードの複製が防止されます。実際に変更される唯一の点は、オブジェクトを IDataReader からクラスに変換する方法です。これにより、ExecuteReader メソッドの呼び出し元は、特定の変換を行うコードを提供できます。

オブジェクトを 1:1 でマッピングし、それらを自動的に変換する方法を提供しているため、これは当てはまらないかもしれませんが、私の場合、それに頼ることはできません。

于 2012-12-28T20:56:34.727 に答える