未处理的类型' System.StackOverflowException'发生在EntityFramework中

时间:2015-04-16 15:17:41

标签: c# entity-framework

我正在尝试加密一些数据,其中我的表有五十万条记录。灵感来自这里的答案 - Fastest Way of Inserting in Entity Framework - 我试图通过调用递归函数来更新我的更新:

IDBContext context;
try{
    context = new MyDbContext();
    context.Configuration.AutoDetectChangesEnabled = false;
    EncryptFields(context, 500, (count / 500));
}
finally{
   if (context != null)
   {
       context.Dispose();
    }
}

这里的递归函数:

private static void EncryptFields(IDBContext context, int batchSize, int maxRetries)
    {
        Debug.WriteLine(maxRetries.ToString());
        if (maxRetries == 0)
        {
            return;
        }
        var phones = context.Phones
                            .Where(p => !(p.Number == null 
                                       || p.Number.Trim() == String.Empty))
                            .Take(batchSize)
                            .ToList();

        if (phones.Count() > 0)
        {
            foreach (var phone in phones)
            {
                phone.Enc_Number = Encrypt(phone.Number);
            }
            context.SaveChanges();
            context.Dispose();
            context = new MyDBContext();
            context.Configuration.AutoDetectChangesEnabled = false;

            EncryptFields(context, batchSize, --maxRetries);
        }
    }

我开始时的maxRetry值为1270,但是当它降到360时,我得到了一个StackOverflow异常:

var phones = context.Phones...

鉴于我处理了上下文并在更新每500条记录后重新创建它,我不确定为什么会收到此异常。

1 个答案:

答案 0 :(得分:0)

重复运行时堆栈中EncryptFields的调用深度看起来像这样(例如,第一次调用它的深度为10):

10, 11, 12, ...

对EF查询的调用深度如下所示:

11, 12, 13, ...

假设您可以访问的最大深度为N.然后,当您对EncryptFields的呼叫位于深度N时,它将尝试在深度N + 1处调用EF查询。这是为什么要在EF查询中获取StackOverflowException而不是直接在递归方法EncryptFields中。

这不是EF问题;异常恰好在那里表现出来,因为您的EF查询深入了解了EncryptFields方法。解决这个问题的方法就是消除递归。

private static void EncryptFields(IDBContext context, int batchSize, int maxRetries)
{
    while (true)
    {
        Debug.WriteLine(maxRetries.ToString());
        if (maxRetries == 0)
        {
            return;
        }
        var phones = context.Phones
            .Where(p => !(p.Number == null || p.Number.Trim() == ""))
            .Take(batchSize)
            .ToList();

        if (phones.Count() > 0)
        {
            foreach (var phone in phones)
            {
                phone.Enc_Number = Encrypt(phone.Number);
            }
            context.SaveChanges();
            context.Dispose();
            context = new MyDBContext();
            context.Configuration.AutoDetectChangesEnabled = false;

            maxRetries--;
            continue;
        }
        else
        {
            break;
        }
    }
}
相关问题