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

Udi*_*-On 8 entity-framework one-to-many varbinarymax entity-framework-6

在我的WebAPI Web应用程序中,我向表中添加了varbinary(max)字段,并向POCO(BatchCharge)添加了byte []字段.该实体具有子实体(Charge).

Visual Studio 2013,实体框架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; }
}
Run Code Online (Sandbox Code Playgroud)

映射在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);
    }
}
Run Code Online (Sandbox Code Playgroud)

使用以下方法检索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));
        }
    }
Run Code Online (Sandbox Code Playgroud)

我得到一个OutOfMemoryException.当我在上面的行中断并尝试查看查询结果时,我看到错误"由于内存不足异常,函数评估已被禁用".见下面的截图.

评估Linq后的调试器视图

这告诉我在EF6内部发生内存不足异常.

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

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

当我作为孩子上传600次充电的BatchCharge时,问题就出现了.正如我所提到的,这不是文件大小问题,因为文件大小为27KB.

如果这里有循环引用,它应该发生在我拥有的许多其他类似配置的关系中.或者是字节数组字段与父/子关系一起创建问题?如果是这样,怎么样?

编辑: 当我用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; }
         }
Run Code Online (Sandbox Code Playgroud)
    <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>
Run Code Online (Sandbox Code Playgroud)

Udi*_*-On 3

感谢@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; }
}
Run Code Online (Sandbox Code Playgroud)