将一个巨大的列表与 Entity Framework 中的数据库 table 条记录进行比较

Compare an huge list with a database table records in Entity Framework

我有一个巨大的字符串列表,我想将数据库表的记录与它进行比较。什么是最好的解决方案?

你可以假设指定表的名称是ATable,它的结构是这样的:

public class ATable
{
    [Key]
    public long Id{get;set;}
    [Key]
    public long Name{get;set;}
}

我写了下面的代码

using(var context = new MyDbContext())
{
    context.Log = (log) => {Console.WriteLine(log)};
    var result = context.ATables.Where(item => hugeList.Contains(item.Name)).ToList();
}

我检查了生成的日志,我看到上面的代码转换为 SQL IN(...) 语句并且由于列表应用程序崩溃的巨大。

我确定有解决这个问题的好方法,那么请专业人士告诉我一个正确的方法。

谢谢

EF 6 Alpha 1 起,EF 包含一项改进,可加速 Enumerable.Contains 的翻译。

如果您使用的是早期版本的 EF,或者您的列表太大,正如@Dan-o 所建议的,您可以将庞大的列表分成更小的块。为此,您可以使用@divega 在此 post 中编写的解决方案。下面我根据您的问题上下文调整该解决方案:

public partial class MyDbContext
{
    public IEnumerable<ATable> GetElements(IEnumerable<long> hugeList, int chunkSize = 100)
    {
        foreach (var chunk in hugeList.Chunk(chunkSize))
        {
            var q = ATables.Where(a => chunk.Contains(a.Name));
            foreach (var item in q)
            {
                yield return item;
            }
        }
    }
}

切片可枚举序列的扩展方法:

public static class EnumerableSlicing
{

    private class Status
    {
        public bool EndOfSequence;
    }

    private static IEnumerable<T> TakeOnEnumerator<T>(IEnumerator<T> enumerator, int count,
        Status status)
    {
        while (--count > 0 && (enumerator.MoveNext() || !(status.EndOfSequence = true)))
        {
            yield return enumerator.Current;
        }
    }

    public static IEnumerable<IEnumerable<T>> Chunk<T>(this IEnumerable<T> items, int chunkSize)
    {
        if (chunkSize < 1)
        {
            throw new ArgumentException("Chunks should not be smaller than 1 element");
        }
        var status = new Status { EndOfSequence = false };
        using (var enumerator = items.GetEnumerator())
        {
            while (!status.EndOfSequence)
            {
                yield return TakeOnEnumerator(enumerator, chunkSize, status);
            }
        }
    }
}

那么你可以这样做:

var result= context.GetElements(hugelist).ToList();