Ошибка Dynamics CRM Xrm Tooling Не удалось выделить буфер управляемой памяти размером 2 147 483 647 байт.

Я создал XRMTool (WPF) для извлечения данных из Dynamics CRM Online в файл XML. Выходной файл, вероятно, может иметь миллион строк, но я получаю следующую ошибку.

Не удалось выделить буфер управляемой памяти размером 2 147 483 647 байт. Объем доступной памяти может быть низким.

Я могу добавить некоторые фильтры и уменьшить количество строк, но в соответствии с требованиями приложения мне нужно извлечь данные как минимум за месяц за один раз, что составит около миллиона строк.

Как увеличить буфер памяти в приложении WPF?

Ниже приведен мой код

            string fetchaudit = @"<fetch version='1.0' mapping='logical'  output-format='xml-platform'>
        <entity name='audit'>
        <attribute name='action' />
        <attribute name='auditid' />
        <attribute name='callinguserid' />
        <attribute name='objecttypecode' />
        <attribute name='createdon' />
        <attribute name='objectid' />
        <attribute name='objectid' />
        <attribute name='operation' />
        <attribute name='regardingobjectid' />
        <attribute name='transactionid' />
        <attribute name='userid' />
        <filter type='and'>
        <condition attribute='createdon' operator='on-or-after' value='" + Fromdate + @"' />
        <condition attribute='createdon' operator='on-or-before' value='" + Todate + @"' />
        </filter>
        </entity>
       </fetch>";
     while (true)
       {
            string xml = CreateXml(fetchaudit, pagingCookie, pageNumber, fetchCount);
            RetrieveMultipleRequest fetchRequest1 = new RetrieveMultipleRequest
            {
                Query = new FetchExpression(xml) // Error occurs here when page number reaches 100
            };
            EntityCollection returnCollection = ((RetrieveMultipleResponse)_ctrl.CrmConnectionMgr.CrmSvc.Execute(fetchRequest1)).EntityCollection;

           // var collection = _ctrl.CrmConnectionMgr.CrmSvc.GetEntityDataByFetchSearchEC(xml);
            if (returnCollection != null)
           {
                if (returnCollection.Entities.Count >= 0)
                    Entities.AddRange(returnCollection.Entities);

            }
            if (returnCollection.MoreRecords)
            {
                pageNumber++;
                pagingCookie = returnCollection.PagingCookie;
            }
            else
            {
                break;
            }
        } // end while

Я использую следующий подход из SDK для разбиения по страницам SampleCode\CS\GeneralProgramming\Queries\FetchPagingWithCookie.cs (https://msdn.microsoft.com/en-us/library/gg309717.aspx)


person nick    schedule 09.09.2017    source источник
comment
Возможно, опубликуйте код, который вы используете для извлечения из CRM. Вы просматриваете данные CRM?   -  person Aron    schedule 09.09.2017
comment
Я отредактировал вопрос с кодом. Да, я использую пейджинг.   -  person nick    schedule 10.09.2017


Ответы (1)


Скорее всего, исключение не происходит при первом запросе, если это так, уменьшите количество возвращаемых строк.

Ваша текущая проблема заключается в том, что вы храните все в памяти до конца извлечения

Entities.AddRange(returnCollection.Entities);

Коллекция Entities быстро растет, но при добавлении не происходит сбоев, потому что выделение памяти происходит при фактическом извлечении SDK.

Чтобы сериализовать результаты запроса как единую коллекцию с помощью DataContractSerializer, вы можете использовать следующую реализацию IEnumerable для чтения данных по пакетам (и дополнительные пояснения к коду):

public class XrmEnumerator<T> : IEnumerator<T> where T : Entity
{
    private readonly Queue<T> _collected = new Queue<T>();
    private IOrganizationService _service;
    private QueryExpression _query;
    private string _lastCookie;
    private bool _moreRecords;

    public T Current { get; private set; }
    object IEnumerator.Current => Current;

    public XrmEnumerator(IOrganizationService service, QueryExpression query)
    {
        _service = service;
        _query = query;
        if (query.PageInfo == null)
            query.PageInfo = new PagingInfo
            {
                Count = 5000,
                PageNumber = 1
            };
        FillThePack();
    }

    private void FillThePack()
    {
        var result = _service.RetrieveMultiple(_query);
        _lastCookie = result.PagingCookie;
        result.Entities.ToList().ForEach(e=>_collected.Enqueue(e.ToEntity<T>()));
        _moreRecords = result.MoreRecords;
    }

    public void Dispose()
    {
        _service = null;
        _query = null;
    }

    public bool MoveNext()
    {
        if(_collected.Count == 0)
        {
            if (!_moreRecords)
            {
                return false;
            }
            _query.PageInfo.PagingCookie = _lastCookie;
            _query.PageInfo.PageNumber++;
            FillThePack();
        }
        Current = _collected.Dequeue();
        return true;
    }

    public void Reset()
    {
        _query.PageInfo.PagingCookie = string.Empty;
        _query.PageInfo.PageNumber = 1;
    }
}

public class XrmEnumerable<T> : IEnumerable<T> where T : Entity
{
    private readonly XrmEnumerator<T> _enumerator;

    public XrmEnumerable(IOrganizationService service, QueryExpression query)
    {
        _enumerator = new XrmEnumerator<T>(service, query);
    }

    public IEnumerator<T> GetEnumerator() => _enumerator;

    IEnumerator IEnumerable.GetEnumerator()
    {
        return _enumerator;
    }

    public virtual void Add(T entity)
    {
        // do your code on item deserialization
    }
}

он использует QueryExpression, а не FetchXml, но вы можете легко преобразовать его

пример использования:

var enumerable = new XrmEnumerable<Contact>(service, query);
var serializer = new DataContractSerializer(typeof(XrmEnumerable<Contact>));
using (var file = File.OpenWrite("contacts.xml"))
    serializer.WriteObject(file, enumerable);

Кроме того, вы можете создать дочерний класс XrmEnumerable и выполнить свою логику в функции Add.

person ASpirin    schedule 10.09.2017