1

我目前正在实现一个用于缓存的 MongoDB 数据库。

我制作了一个非常通用的客户端,保存方法如下:

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-garden 解决方案(多个进程),这会导致并发问题。如果我在另一个用户重新加载页面时保存并重新加载缓存,有时它会引发 E11000 重复键错误集合。

命令 createIndexes 失败:E11000 重复键错误收集:缓存。人员索引:Id_1_Name_1_Email_1 重复键:{:1,:“John Doe”,:“foo@bar.com”}。

考虑到这是一个运行多个 IIS 进程的网络花园,锁定不会有多大用处。考虑到批量写入应该是线程安全的,我有点困惑。我已经研究了更新数据,但是将我们的客户更改为特定类型并更新每个字段将花费太长时间,并且感觉像是不必要的工作。因此,我正在寻找一个非常通用的解决方案。

更新 删除了插入和删除。将其更改为 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);
}
4

0 回答 0