現在、キャッシュ用に MongoDB データベースを実装しています。
save メソッドが次のように機能する、非常に一般的なクライアントを作成しました。
public virtual void SaveAndOverwriteExistingCollection<T>(string collectionKey, T[] data)
{
if (data == null || !data.Any())
return;
var collection = Connector.MongoDatabase.GetCollection<T>(collectionKey.ToString());
var filter = new FilterDefinitionBuilder<T>().Empty;
var operations = new List<WriteModel<T>>
{
new DeleteManyModel<T>(filter),
};
operations.AddRange(data.Select(t => new InsertOneModel<T>(t)));
try
{
collection.BulkWrite(operations, new BulkWriteOptions { IsOrdered = true});
}
catch (MongoBulkWriteException mongoBulkWriteException)
{
throw mongoBulkWriteException;
}
}
他のクライアントでこのメソッドを呼び出すと、次のようになります。
public Person[] Get(bool bypassCache = false)
{
Person[] people = null;
if (!bypassCache)
people = base.Get<Person>(DefaultCollectionKeys.People.CreateCollectionKey());
if (people.SafeAny())
return people;
people = Client<IPeopleService>.Invoke(s => s.Get());
base.SaveAndOverwriteExistingCollection(DefaultCollectionKeys.People.CreateCollectionKey(), people);
return people;
}
データをバックエンドに保持した後、Get メソッドを呼び出して引数 true を渡して、MongoDB からキャッシュをリロードします。したがって、すべてのデータをリロードします。
これは、ほとんどのユースケースでうまく機能します。しかし、同じアプリケーションに対して Web ガーデン ソリューション (複数のプロセス) をどのように使用しているかを考えると、これは並行性の問題につながります。別のユーザーがページをリロードしているときにキャッシュを保存してリロードすると、E11000 重複キー エラー コレクションがスローされることがあります。
コマンド createIndexes が失敗しました: E11000 重複キー エラー コレクション: cache.Person インデックス: Id_1_Name_1_Email_1 重複キー: { : 1, : "John Doe", : "foo@bar.com" }.
これが複数の IIS プロセスが実行されている Web ガーデンであることを考えると、ロックはあまり役に立ちません。一括書き込みがどのようにスレッドセーフであるべきかを考えると、私は少し困惑しています。データのアップサートについて調べましたが、クライアントをタイプ固有に変更し、各フィールドを更新するには時間がかかりすぎて、不要な作業のように感じます。したがって、私は非常に一般的な解決策を探しています。
UPDATE 挿入と削除を削除しました。ReplaceOneModel のコレクションに変更しました。現在、コレクション内の最後の要素のみが永続化されるという問題が発生しています。
public virtual void SaveAndOverwriteExistingCollection<T>(string collectionKey, T[] data)
{
if (data == null || !data.Any())
return;
var collection = Connector.MongoDatabase.GetCollection<T>(collectionKey.ToString());
var filter = new FilterDefinitionBuilder<T>().Empty;
var operations = new List<WriteModel<T>>();
operations.AddRange(data.Select(t => new ReplaceOneModel<T>(filter, t) { IsUpsert = true }));
try
{
collection.BulkWrite(operations, new BulkWriteOptions { IsOrdered = true });
}
catch (MongoBulkWriteException mongoBulkWriteException)
{
throw mongoBulkWriteException;
}
}
811 個のアイテムのコレクションを渡したところ、このメソッドが実行された後、最後のアイテムのみがコレクション内で見つかります。
永続化される DTO の例:
public class TranslationSetting
{
[BsonId(IdGenerator = typeof(GuidGenerator))]
public object ObjectId { get; set; }
public string LanguageCode { get; set; }
public string SettingKey { get; set; }
public string Text { get; set; }
}
このインデックスでは:
string TranslationSettings()
{
var indexBuilder = new IndexKeysDefinitionBuilder<TranslationSetting>()
.Ascending(_ => _.SettingKey)
.Ascending(_ => _.LanguageCode);
return MongoDBClient.CreateIndex(DefaultCollectionKeys.TranslationSettings, indexBuilder);
}