EF6 OutOfMemoryException 使用 varbinary(max) 评估实体 属性

EF6 OutOfMemoryException Evaluating Entity with varbinary(max) Property

在我的 WebAPI 网络应用程序中,我向 table 添加了一个 varbinary(max) 字段,向 POCO (BatchCharge) 添加了一个 byte[] 字段。该实体有一个子实体 (Charge)。

Visual Studio 2013,Entity Framework 6,SQL 服务器 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);
    }
}

使用以下方法检索 BatchCharge 列表时:

    [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。当我中断上面的行并尝试查看查询结果时,我看到的是错误 "The function evaluation was disabled because of an out of memory exception."。请参阅下面的屏幕截图。

这告诉我内存不足异常发生在 EF6 中。

我看过几个关于如何增加进程内存的相关回答。我不相信这是问题所在。测试数据包括 BatchCharge(父)中的六行 table,最大文件大小为 27 KB!

该文件是包含子实体(费用)信息的 CSV 文件。使用此模型使用文件数据上传和保存 BatchCharges 没有问题。我还成功地将它用于每个 BatchCharge 的少量费用(子实体)。

当我小时候上传一个包含 600 个 Charges 的 BatchCharge 时,问题就开始了。正如我提到的,这不是文件大小的问题,因为文件大小是 27KB。

如果这里有循环引用,它应该发生在我拥有的许多其他类似配置的关系中。还是字节数组字段与 parent/child 关系一起产生问题?如果是这样,如何?

编辑: 当我用 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; }
         }
    <body bgcolor="white">

            <span><H1>Server Error in '/' Application.<hr width=100% size=1 color=silver></H1>

            <h2> <i>Exception of type 'System.OutOfMemoryException' was thrown.</i> </h2></span>

            <font face="Arial, Helvetica, Geneva, SunSans-Regular, sans-serif ">

            <b> Description: </b>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.

            <br><br>

            <b> Exception Details: </b>System.OutOfMemoryException: Exception of type 'System.OutOfMemoryException' was thrown.<br><br>

            <b>Source Error:</b> <br><br>

            <table width=100% bgcolor="#ffffcc">
               <tr>
                  <td>
                      <code>

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.</code>

                  </td>
               </tr>
            </table>

            <br>

            <b>Stack Trace:</b> <br><br>

            <table width=100% bgcolor="#ffffcc">
               <tr>
                  <td>
                      <code><pre>

[OutOfMemoryException: Exception of type &#39;System.OutOfMemoryException&#39; 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&amp; completedSynchronously) +117
</pre></code>

                  </td>
               </tr>
            </table>

            <br>

            <hr width=100% size=1 color=silver>

            <b>Version Information:</b>&nbsp;Microsoft .NET Framework Version:4.0.30319; ASP.NET Version:4.7.3056.0

            </font>

    </body>

感谢@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; }
}