使用存储库模式时的MongoDB和大型数据集 [英] MongoDB and Large Datasets when using a Repository pattern

查看:77
本文介绍了使用存储库模式时的MongoDB和大型数据集的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

好的,因此在工作中,我们正在使用MVC C#和amp;开发系统. MongoDB.刚开始开发时,我们决定遵循Repository模式(这真是个麻烦!)可能是个好主意,下面的代码可以让您大致了解当前已实现的内容.

Okay so at work we are developing a system using MVC C# & MongoDB. When first developing we decided it would probably be a good idea to follow the Repository pattern (what a pain in the ass!), here is the code to give an idea of what is currently implemented.

MongoRepository类:

The MongoRepository class:

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>();
    }
}

IRepository接口类:

The IRepository interface class:

public interface IRepository { }

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

    string StoreNamePrepend { get; set; }

    string StoreNameAppend { get; set; }

    IQueryable<T> SearchFor();

    /* misc code */

}

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

The repository is then instantiated using Ninject but without that it would look something like this (just to make this a simpler example):

MongoRepository<Client> clientCol = new MongoRepository<Client>();

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

Here is the code used for the search pages which is used to feed into a controller action which outputs JSON for a table with DataTables to read. Please note that the following uses DynamicLinq so that the linq can be built from string input:

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

现在的问题是,如果集合中有很多记录(准确的说是99,905),那么如果字段中的数据不是很大,例如我们的Key字段是5个字符的固定长度字符串,并且可以使用此查询略过和精打细算.但是,如果类似ClientDescription的内容可以更长,我可以从查询的前面(即第1页)排序"和取"罚款,但是当我使用Skip = 99900&取= 10会产生以下内存错误:

Now the problem is that if the collection has a lot of records (99,905 to be exact) everything works fine if the data in a field isn't very large for example our Key field is a 5 character fixed length string and I can Skip and Take fine using this query. However if it is something like ClientDescription can be much longer I can 'Sort' fine and 'Take' fine from the front of the query (i.e. Page 1) however when I page to the end with Skip = 99900 & Take = 10 it gives the following memory error:

发生类型为'MongoDB.Driver.MongoCommandException'的异常 在MongoDB.Driver.dll中,但未在用户代码中处理

An exception of type 'MongoDB.Driver.MongoCommandException' occurred in MongoDB.Driver.dll but was not handled in user code

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

Additional information: Command aggregate failed: exception: Sort exceeded memory limit of 104857600 bytes, but did not opt in to external sorting. Aborting operation. Pass allowDiskUse:true to opt in..

好的,我想这很容易理解.我在线上看了看,建议的大多数内容都是使用Aggregation和"allowDiskUse:true",但是由于我在IRepository中使用IQueryable,所以我无法开始使用IAggregateFluent<>,因为随后您需要将与MongoDB相关的类公开给IRepository违反IoC负责人.

Okay so that is easy to understand I guess. I have had a look online and mostly everything that is suggested is to use Aggregation and "allowDiskUse:true" however since I use IQueryable in IRepository I cannot start using IAggregateFluent<> because you would then need to expose MongoDB related classes to IRepository which would go against IoC principals.

是否有任何方法可以强制IQueryable使用它,或者有人知道我可以在不违反IoC主体的情况下访问IAggregateFluent的方法吗?

Is there any way to force IQueryable to use this or does anyone know of a way for me to access IAggregateFluent without going against IoC principals?

我感兴趣的一件事是为什么排序适用于第1页(开始= 0,采用= 10),但是当我搜索到末尾时却失败了……肯定必须对所有内容进行排序才能使我能够获取第1页中的项目,但不应该(开始= 99900,获取= 10)只需要相同数量的排序",而MongoDB应该只向我发送最后5条左右的记录.为什么两种排序都没有发生此错误?

答案

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

Okay so with the help of @craig-wilson upgrading to the newest version of MongoDB C# drivers and changing the following in MongoRepository will fix the problem:

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

我正在获取System.MissingMethodException,但这是由MongoDB驱动程序的其他副本也需要更新引起的.

I was getting a System.MissingMethodException but this was caused by other copies of the MongoDB drivers needing updated as well.

推荐答案

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

When creating the IQueryable from an IMongoCollection, you can pass in the AggregateOptions which allow you to set AllowDiskUse.

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

这篇关于使用存储库模式时的MongoDB和大型数据集的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆