为什么我的Linq to Entities命令导致堆栈溢出?

时间:2014-01-14 20:22:55

标签: linq-to-entities stack-overflow

我有以下代码:

public List<NoteViewModel> GetAllPerContacts(List<long> contactIds)
{
    // This next line causes a stack overflow
    var contacts = _unitOfWork.ContactRepository.GetQuery()
        .IncludeMultiple(x => x.Notes)
        .Where(x => contactIds.Any(y => y == x.Id))
        .ToList();  

    var noteModels = contacts.SelectMany(x => x.Notes.Select(n => GetNoteModel(n)));

    return noteModels.ToList();
}

如果有大约3000条记录,则第一条语句会导致堆栈溢出。如果删除.Where行,或者记录较少,则运行正常。

有没有更好的方法来执行.Any不会导致堆栈溢出?

根据要求:

public static IQueryable<T> IncludeMultiple<T>(this IQueryable<T> query, 
    params Expression<Func<T, object>>[] includes) where T : class
{
    if (includes != null)
    {
        query = includes.Aggregate(query,
            (current, include) => current.Include(include));
    }

    return query;
}

2 个答案:

答案 0 :(得分:0)

翻译的sql的大小有限制。所以如果有大量contactIds翻译的sql会太大。解决方法是将contactIds拆分为较小的列表并合并结果。像这样:

public List<NoteViewModel> GetAllPerContacts(List<long> contactIds)
{
   var query = _unitOfWork.ContactRepository.GetQuery().IncludeMultiple(x => x.Notes);

   IEnumerable<Contact> contacts = Enumerable.Empty<Contact>();

   long increment = 100;
   long groups = contactIds.Count / increment + 1;
   for(int i=0; i<groups; i++)
   {
     List<long> partialIds = contactIds.Skip(i*increment).Take(increment).ToList();
     contacts = contacts.Concat(query.Where(x => partialIds.Any(y => y == x.Id)).ToList());  
   }       

    var noteModels = contacts.SelectMany(x => x.Notes.Select(n => GetNoteModel(n)));

    return noteModels.ToList();
}

答案 1 :(得分:0)

我忽略了一个非常简单的解决方案......使用.Contains函数。

我将代码修改为:

var contacts = _unitOfWork.ContactRepository.GetQuery()
    .IncludeMultiple(x => x.Notes)
    .Where(x => contactIds.Contains(x.Id))
    .ToList();

它完美无缺。