使用存储库模式时的MongoDB和大数据集

Dwi*_*iea 3 linq mongodb mongodb-.net-driver

好的,在工作中我们正在使用MVC C#和MongoDB开发一个系统.在第一次开发时,我们认为遵循Repository模式可能是一个好主意(屁股中的痛苦!),这里是代码,用于了解当前实现的内容.

MongoRepository类:

public class MongoRepository { }

public class MongoRepository<T> : MongoRepository, IRepository<T>
where T : IEntity
{
    private MongoClient _client;
    private IMongoDatabase _database;
    private IMongoCollection<T> _collection;

    public string StoreName {
        get {
                return typeof(T).Name;
            }
        }
    }

    public MongoRepository() {

        _client = new MongoClient(ConfigurationManager.AppSettings["MongoDatabaseURL"]);
        _database = _client.GetDatabase(ConfigurationManager.AppSettings["MongoDatabaseName"]);

        /* misc code here */

        Init();
    }

    public void Init() {
        _collection = _database.GetCollection<T>(StoreName);
    }

    public IQueryable<T> SearchFor() {
        return _collection.AsQueryable<T>();
    }
}
Run Code Online (Sandbox Code Playgroud)

IRepository接口类:

public interface IRepository { }

public interface IRepository<T> : IRepository
where T : IEntity
{

    string StoreNamePrepend { get; set; }

    string StoreNameAppend { get; set; }

    IQueryable<T> SearchFor();

    /* misc code */

}
Run Code Online (Sandbox Code Playgroud)

然后使用Ninject实例化存储库,但如果没有它,它将看起来像这样(只是为了使这个更简单的例子):

MongoRepository<Client> clientCol = new MongoRepository<Client>();
Run Code Online (Sandbox Code Playgroud)

以下是用于搜索页面的代码,用于输入控制器操作,该操作为要读取的DataTables的表输出JSON.请注意,以下使用DynamicLinq,以便可以从字符串输入构建linq:

tmpFinalList = clientCol
    .SearchFor()
    .OrderBy(tmpOrder) // tmpOrder = "ClientDescription DESC"
    .Skip(Start) // Start = 99900
    .Take(PageLength) // PageLength = 10
    .ToList();
Run Code Online (Sandbox Code Playgroud)

现在的问题是,如果集合有很多记录(准确地说99,905),如果字段中的数据不是很大,一切正常,例如我们的Key字段是一个5字符的固定长度字符串,我可以跳过和使用此查询可以正常使用 但是,如果像ClientDescription这样的东西可以更长,我可以从查询的前面"排序"很好并且"正常"(例如第1页)但是当我以Skip = 99900&Take = 10页面结束时,它给出了以下内存错误:

MongoDB.Driver.dll中出现"MongoDB.Driver.MongoCommandException"类型的异常,但未在用户代码中处理

附加信息:命令聚合失败:异常:排序超出内存限制104857600字节,但未选择外部排序.中止操作.传递allowDiskUse:true以选择加入..

好吧,我想这很容易理解.我在网上看过,大多数建议是使用Aggregation和"allowDiskUse:true"但是因为我在IRepository中使用IQueryable,所以我不能开始使用IAggregateFluent <>因为你需要将MongoDB相关的类公开给IRepository反对IoC校长.

有没有办法强制IQueryable使用它或有没有人知道我访问IAggregateFluent的方式而不违反IoC委托人?

我感兴趣的一件事是为什么排序适用于第1页(Start = 0,Take = 10)但是当我搜索结束时失败...当然必须为我排序所有内容以便能够获取项目第1页的顺序但不应该(Start = 99900,Take = 10)只需要相同数量的'排序',MongoDB应该只发送最后5个左右的记录.两种排序完成后为什么不会发生此错误?


回答

好的,在@ craig-wilson的帮助下升级到最新版本的MongoDB C#驱动程序并更改MongoRepository中的以下内容将解决问题:

public IQueryable<T> SearchFor() {
    return _collection.AsQueryable<T>(new AggregateOptions { AllowDiskUse = true });
}
Run Code Online (Sandbox Code Playgroud)

我收到了System.MissingMethodException,但这是由需要更新的MongoDB驱动程序的其他副本引起的.

Cra*_*son 5

从IMongoCollection创建IQueryable时,您可以传入允许您设置AllowDiskUse的AggregateOptions.

https://github.com/mongodb/mongo-csharp-driver/blob/master/src/MongoDB.Driver/IMongoCollectionExtensions.cs#L53