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

时间:2015-01-01 12:47:08

标签: c# 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(...)语句,并且由于列表应用程序崩溃的严重性。

我确信有一个很好的方法可以解决这个问题,那么专业人士可以向我展示正确的问题。

由于

1 个答案:

答案 0 :(得分:2)

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();