将一个巨大的列表与 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();
我有一个巨大的字符串列表,我想将数据库表的记录与它进行比较。什么是最好的解决方案?
你可以假设指定表的名称是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();