EF6 OutOfMemoryException Оценка объекта с помощью свойства varbinary (max) - PullRequest
0 голосов
/ 28 июня 2018

В моем веб-приложении WebAPI я добавил поле varbinary (max) в таблицу и поле byte [] в POCO (BatchCharge). Эта сущность имеет дочернюю сущность (Charge).

Visual Studio 2013, Entity Framework 6, SQL Server 2014.

Модель данных выглядит следующим образом:

public class BatchCharge
{
    public int ID { get; set; }
    public byte[] FileData { get; set; }
    public virtual ICollection<Charge> Charges { get; set; } 
}

public class Charge
{
    public int ID { get; set; }
    public DateTime CreatedUTC { get; set; }
    public decimal Amount { get; set; }
    public virtual BatchCharge BatchCharge { get; set; }
}

Сопоставление выполняется для объекта Charge (дочерний) следующим образом:

public class ChargeMap : EntityTypeConfiguration<Charge>
{
    public ChargeMap()
    {
        // Primary Key
        HasKey(t => t.ID);

        // Table and Column Mappings
        ToTable("Charge");
        Property(t => t.ID).HasColumnName("ID");
        Property(t => t.ID).IsRequired();

        Property(t => t.CreatedUTC).HasColumnName("CreatedUTC");
        Property(t => t.CreatedUTC).IsRequired();

        Property(t => t.Amount).HasColumnName("Amount");
        Property(t => t.Amount).IsRequired();

        HasRequired(t => t.BatchCharge)
            .WithMany(t => t.Charges)
            .HasForeignKey(d => d.BatchChargeID);
    }
}

При получении списка BatchCharges, используя метод ниже:

    [ActionName("GetBatchCharges")]
    [HttpGet]
    [Route("api/charges/batches")]
    [Authorize(Roles = "Administrator")]
    public HttpResponseMessage GetBatchCharges(int skip = 0,
        int take = 25,
        int statusFilter = 0)
    {
        try
        {
            var batchCharges = _centralDb.BatchCharges.AsQueryable();
            if (statusFilter > 0)
            {
                batchCharges = batchCharges.Where(bc => bc.StatusID == statusFilter);
            }

            // Page and list.
            var allBatchCharges = batchCharges.OrderByDescending(c => c.CreatedUTC);
            var totalCount = allBatchCharges.Count();
            var thePage = allBatchCharges.Skip(take * skip).Take(take).ToList();

            // Transform and return.
            var result = new
            {
                TotalCount = totalCount,
                CurrentPage = skip,
                BatchCharges = thePage.Select(c => MapperFactory.Mapper.Map<BatchCharge, BatchChargeDTO>(c)).ToList()
            };
            return Request.CreateResponse(HttpStatusCode.OK, result);
        }
        catch (Exception ex)
        {
            const string message = "Exception getting batch charges.";
            Logger.Error(ex, message);
            return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, new HttpError(message));
        }
    }

Я получаю исключение OutOfMemoryException. Когда я ломаю строку выше и пытаюсь просмотреть результаты запроса, вместо этого я вижу ошибку «Оценка функции была отключена из-за исключения нехватки памяти». Смотрите скриншот ниже.

Debugger view after evaluating Linq

Это говорит о том, что исключение нехватки памяти происходит внутри EF6.

Я видел несколько связанных ответов о том, как увеличить память процесса. Я не верю, что это проблема. Данные теста включают шесть строк в таблице BatchCharge (parent) и максимальный размер файла 27 КБ!

Файл представляет собой файл CSV с информацией о дочернем объекте (Сборы). У меня нет проблем с загрузкой и сохранением BatchCharges с данными файла с использованием этой модели. Я также успешно использовал его на небольшом количестве сборов (дочерних объектов) для BatchCharge.

Проблема началась, когда я загрузил BatchCharge с 600 зарядами в качестве детей. Как я уже говорил, это не проблема размера файла, потому что размер файла составляет 27 КБ.

Если здесь есть круговая ссылка, это должно происходить во многих других аналогично настроенных отношениях, которые у меня есть. Или поле байтового массива создает проблему в сочетании с отношениями родитель / потомок? Если так, то как?

EDIT: Когда я окружаю код блоком try / catch и выполняю его шаг за шагом в отладчике, он не вызывает исключения в моем коде! Однако в ответ, поступающий в браузер, входит стандартная страница необработанных исключений IIS с ошибкой сервера следующим образом (запустите фрагмент кода, чтобы просмотреть выходные данные):

         body {font-family:"Verdana";font-weight:normal;font-size: .7em;color:black;} 
         p {font-family:"Verdana";font-weight:normal;color:black;margin-top: -5px}
         b {font-family:"Verdana";font-weight:bold;color:black;margin-top: -5px}
         H1 { font-family:"Verdana";font-weight:normal;font-size:18pt;color:red }
         H2 { font-family:"Verdana";font-weight:normal;font-size:14pt;color:maroon }
         pre {font-family:"Consolas","Lucida Console",Monospace;font-size:11pt;margin:0;padding:0.5em;line-height:14pt}
         .marker {font-weight: bold; color: black;text-decoration: none;}
         .version {color: gray;}
         .error {margin-bottom: 10px;}
         .expandable { text-decoration:underline; font-weight:bold; color:navy; cursor:hand; }
         @media screen and (max-width: 639px) {
          pre { width: 440px; overflow: auto; white-space: pre-wrap; word-wrap: break-word; }
         }
         @media screen and (max-width: 479px) {
          pre { width: 280px; }
         }
    

            Server Error in '/' Application.

             Exception of type 'System.OutOfMemoryException' was thrown. 

            

 Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

            

Exception Details: System.OutOfMemoryException: Exception of type 'System.OutOfMemoryException' was thrown.

Source Error:

An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.
Stack Trace:

[OutOfMemoryException: Exception of type 'System.OutOfMemoryException' was thrown.] System.IO.MemoryStream.set_Capacity(Int32 value) +89 System.IO.MemoryStream.EnsureCapacity(Int32 value) +90 System.IO.MemoryStream.Write(Byte[] buffer, Int32 offset, Int32 count) +326 Microsoft.VisualStudio.Web.PageInspector.Runtime.Tracing.ArteryFilter.Write(Byte[] buffer, Int32 offset, Int32 count) +106 System.Web.HttpWriter.FilterIntegrated(Boolean finalFiltering, IIS7WorkerRequest wr) +475 System.Web.HttpResponse.FilterOutput() +154 System.Web.CallFilterExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +80 System.Web.HttpApplication.ExecuteStepImpl(IExecutionStep step) +247 System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +117


Информация о версии: Microsoft .NET Framework Версия: 4.0.30319; ASP.NET версия: 4.7.3056.0

1 Ответ

0 голосов
/ 02 июля 2018

Благодаря @IvanStoev обнаружил проблему в DTO: они ссылались на свойства EF (выделено ниже), что вызывало исключения из памяти при больших наборах данных.

public class BatchChargeDTO
{
    public int ID { get; set; }
    public byte[] FileData { get; set; }
    // Problem is here: type should be ChargeDTO!!
    public ICollection<Charge> Charges { get; set; }
}

public class ChargeDTO
{
    public int ID { get; set; }
    public DateTime CreatedUTC { get; set; }
    public decimal Amount { get; set; }
    public int? BatchChargeID { get; set; }
    // Problem is here: type should be BatchChargeDTO!!
    public BatchCharge BatchCharge { get; set; }
}
...