【问题标题】:Compare an huge list with a database table records in Entity Framework将一个巨大的列表与 Entity Framework 中的数据库表记录进行比较
【发布时间】:2015-02-28 02:55:56
【问题描述】:

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

您可以假设指定表的名称为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(...) 语句,并且由于列表应用程序崩溃的巨大。

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

谢谢

【问题讨论】:

  • 您可以使用context.ATables.ToList()将其作为对象保存在内存中。然后检查两个 .net 对象之间的条件。
  • 你是对的,但如果我的表的记录也很大,那又如何呢?
  • 在我看来,您可以创建一个新表。然后将此列表项插入此表。然后在 Linq-To-Entity 的帮助下连接这两个表。并且得到结果后,可以截断第一个表。
  • 这主意不错,但我喜欢收集更多建议。谢谢
  • 您可能会考虑将hugeList 分成更小的块。例如,一次 20 个值。

标签: c# entity-framework


【解决方案1】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-09
    • 2020-06-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多