【发布时间】:2020-05-10 08:35:57
【问题描述】:
作为Contains 的实现,我正在使用Andy Dent 的written 稍作调整的方法来查询我的领域数据库:
private IQueryable<Entry> FilterEntriesByIds(IQueryable<Entry> allEntries, int[] idsToMatch)
{
// Fancy way to invent Contains<>() for LINQ
ParameterExpression pe = Expression.Parameter(typeof(Entry), "Entry");
Expression chainedByOr = null;
Expression left = Expression.Property(pe, typeof(Entry).GetProperty("Id"));
for (int i = 0; i < idsToMatch.Count(); i++) {
Expression right = Expression.Constant(idsToMatch[i]);
Expression anotherEqual = Expression.Equal(left, right);
if (chainedByOr == null)
chainedByOr = anotherEqual;
else
chainedByOr = Expression.OrElse(chainedByOr, anotherEqual);
}
MethodCallExpression whereCallExpression = Expression.Call(
typeof(Queryable),
"Where",
new Type[] { allEntries.ElementType },
allEntries.Expression,
Expression.Lambda<Func<Entry, bool>>(chainedByOr, new ParameterExpression[] { pe }));
return allEntries.Provider.CreateQuery<Entry>(whereCallExpression);
}
只要我传递的 id 少于 2-3K,这一切都可以正常工作,当我使用大量的 id 时,应用程序就会崩溃,似乎是 stackoverflow 异常。
解决这个问题的第一个想法是将查询分成块然后合并结果,但是Concat 和Union 方法在这些领域IQueryables 上不起作用,所以,我还能如何合并这样的分块结果?还是有其他解决方法?
我不能只是将结果转换为列表或其他东西然后合并,我必须将领域对象返回为IQueryable<>
调用栈:
=================================================================
Native Crash Reporting
=================================================================
Got a SIGSEGV while executing native code. This usually indicates
a fatal error in the mono runtime or one of the native libraries
used by your application.
=================================================================
No native Android stacktrace (see debuggerd output).
=================================================================
Basic Fault Address Reporting
=================================================================
Memory around native instruction pointer (0x7c326075c8):0x7c326075b8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x7c326075c8 fd 7b bb a9 fd 03 00 91 a0 0b 00 f9 10 0e 87 d2 .{..............
0x7c326075d8 10 d0 a7 f2 90 0f c0 f2 b0 0f 00 f9 10 00 9e d2 ................
0x7c326075e8 f0 d5 a9 f2 90 0f c0 f2 b0 13 00 f9 a0 a3 00 91 ................
=================================================================
Managed Stacktrace:
============================
=====================================
at Realms.QueryHandle:GroupBegin <0x00000>
at Realms.RealmResultsVisitor:VisitCombination <0x0007f>
at Realms.RealmResultsVisitor:VisitBinary <0x003f7>
at System.Linq.Expressions.BinaryExpression:Accept <0x00073>
at System.Linq.Expressions.ExpressionVisitor:Visit <0x00087>
at Realms.RealmResultsVisitor:VisitCombination <0x000d7>
at Realms.RealmResultsVisitor:VisitBinary <0x003f7>
at System.Linq.Expressions.BinaryExpression:Accept <0x00073>
at System.Linq.Expressions.ExpressionVisitor:Visit <0x00087>
at Realms.RealmResultsVisitor:VisitCombination <0x000d7>
at Realms.RealmResultsVisitor:VisitBinary <0x003f7>
at System.Linq.Expressions.BinaryExpression:Accept <0x00073>
at System.Linq.Expressions.ExpressionVisitor:Visit <0x00087>
at Realms.RealmResultsVisitor:VisitCombination <0x000d7>
at Realms.RealmResultsVisitor:VisitBinary <0x003f7>
at System.Linq.Expressions.BinaryExpression:Accept <0x00073>
at System.Linq.Expressions.Ex
pressionVisitor:Visit <0x00087>
UPD
我找到了引发此错误的元素的确切数量:3939,如果我传递的值大于该值,它就会崩溃。
【问题讨论】:
-
这里可能有XY problem 的案例。 :) 不会向查询发送这么多 ID。相反,您可以将它们提取到单独的数据库表中(您可能不必在内存中保存数千个 ID)并在查询中使用它。
-
@ŠimonKocúrek 考虑到这是一种搜索机制,每次进行查询时从数据库中写入和读取的开销会不会太大?
-
如果查询有数据库提供程序,请注意一个sql命令中的最大参数数,对于SQL Server是2100。
-
@MartinStaufcik 是的,这似乎是问题所在,但我怎样才能避免这样做并在不崩溃的情况下获得“相同”的结果?这就是问题
-
由于是包含操作,可以发送多个查询,然后合并结果。
标签: c# optimization realm expression-trees