アクティブレコードパターン

C#にActive Recordテンプレートを実際に適用することについてお話したいと思います。 このクラスは、構造の抽出とデータベースへの書き込みを実装します。 ビジネスロジックは、次のレベルの抽象化が行われ、通常の構造のようなオブジェクトを操作できます。



私が例として考える中心的なケースは、データベースからCountryディレクトリを操作することです。これは頻繁に読み取られますが、ほとんど変更されません。



ビジネスロジックコードでアクティブなレコードオブジェクトを使用すると、次のようになります。



Country russia = Country.All[“Russia”];
      
      









国にはパブリックコンストラクターがなく、オブジェクトの取得は、 Dictionary <string、Country> Allメソッドにアクセスすることによってのみ可能です。



次に、このクラスがどのように内部から構築されるかについて詳しく説明します。



レコードコンストラクタ





 public readonly string name; private Country(IDataRecord record) { name = record.GetString(0); }
      
      







コンストラクターのプライバシーのため、コンストラクターの正しい使用を期待できます。 そしてクラス内のみ。

たとえば、次のように:



 private static Dictionary<string, Country> _all = null; private static Dictionary<string, Country> LoadDictionary() { _all = new Dictionary<string, Country>(); IDataReader reader = DBWrapper.GetReader(sqlSelect); try { while (reader.Read()) { Country item = new Country(reader); _all.Add(item.name, item); } } finally { reader.Close(); } return _all; }
      
      







sqlSelectは、コンストラクターに必要なフィールド順序ですべてのレコードを読み取るためのプライベート定数です。



DBWrapperは、データベースでの作業をカプセル化する自己記述型のクラスです。 彼のおかげで、このレベルでは、特定の実装を指定せずに、インターフェイスを操作するだけで済みます。



追加 -記事のコードを簡潔にするために、一般的なレジストリに新しいエントリを追加することは隠されています。



すべての辞書





ここでも複雑なことはありません:



 public static Dictionary<string, Country> All { get { return _all ?? LoadDictionary(); }}
      
      







その結果、最初の呼び出しでディレクトリの読み込みが遅れます。



プライベート変数_allは、このコードでのみ使用します。 残念ながら、C#では、その使用をクラス全体未満に制限することはできません。 たとえば、パブリックメソッドでは、その適用の危険性が残っています。 複数のスレッドで作業する場合に実際に問題になるのは何ですか。



これは私が議論したい最初の質問です:_all変数の可視性をさらに制限する方法は?



マルチスレッド同期





この遅延読み込みメソッドはまだマルチスレッドに適していないため、 LoadStatusクラスを追加しました。



private static readonly LoadStatus statusCountryList = new LoadStatus(“country”);







すべてのディレクトリのステータスリストでステータスを識別するには、ステータスの名前が必要です。 しかし、それについては後で。



 private static Dictionary<string, Country> _all = null; public static Dictionary<string, Country> All { get { if ( !statusCountryList.IsCompleted ) { lock (statusCountryList) { if ( !statusCountryList.IsCompleted ) { statusCountryList.Start(); _all = new Dictionary<string, Country>(); IDataReader reader= DBWrapper.GetReader(sqlSelect); try { while (reader.Read()) Add(new Country(reader)) statusCountryList.Finish(_all.Count); } catch Exception ex { statusCountryList.Error(ex); } finally { reader.Close(); } }}} return _all; }}
      
      







パスタはたくさんありますが、アーキテクチャからのボーナスとして、マルチスレッドとディレクトリのヘルスレポートがあります。



LoadStatusは、ディレクトリ内のヘルスデータの同期と収集を隠します。



さらに、 LoadStatusをリセットすることにより、その場でディレクトリをリロードすることが可能になります。

_allの 読み取り専用を拒否したのは、この機会のためです。



ジェネリッククラス





このソリューションは非常に便利でエレガントであることが判明したため、すべてのプロジェクトの多数のディレクトリで使用しています。 そしてこのコードをジェネリッククラスに変えたいと強く望んでいます。

ただし、C#構文はこれを許可しません。



この決定についてどう思いますか?

このソリューションをジェネリックに変える方法は何ですか?



All Articles