SQLite.net表查询引发NullReferenceException异常。

8
我正在使用以下代码从SQLite数据库中的给定表中查询一些数据(平台为WP81,但我想这在这里并不重要)。
return await Connection.Table<WorkDay>().Where(wd => wd.Date >= @from && wd.Date <= to).ToListAsync().ConfigureAwait(false);

当我执行我的代码时,在Where语句中出现了NullReferenceException异常。当我移除where条件时,一切都正常运行。
return await Connection.Table<WorkDay>().ToListAsync().ConfigureAwait(false);

为了确保我的表中的所有条目都是有效的,并且日期列中没有空值,我使用了一个SQL工具来查看SQLite数据库。
由于我无法调试lambda表达式,所以我有点卡住了,不知道如何解决这个问题。我的假设是由于异步处理出了问题。
编辑: 这里是异常的完整堆栈跟踪信息。
{System.NullReferenceException: Object reference not set to an instance of an object.
   at SQLite.Net.TableQuery`1.CompileExpr(Expression expr, List`1 queryArgs)
   at SQLite.Net.TableQuery`1.CompileExpr(Expression expr, List`1 queryArgs)
   at SQLite.Net.TableQuery`1.CompileExpr(Expression expr, List`1 queryArgs)
   at SQLite.Net.TableQuery`1.GenerateCommand(String selectionList)
   at SQLite.Net.TableQuery`1.GetEnumerator()
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
   at SQLite.Net.Async.AsyncTableQuery`1.<ToListAsync>b__0()
   at System.Threading.Tasks.Task`1.InnerInvoke()
   at System.Threading.Tasks.Task.Execute()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
   at TimeStamp.Core.Services.DataService.<GetWorkDays>d__c.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at TimeStamp.Core.ViewModel.MainViewModel.<LoadWorkDays>d__1a.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.AsyncMethodBuilderCore.<ThrowAsync>b__3(Object state)}

编辑2:

我再进一步尝试并发现以下内容。

var query = Connection.Table<WorkDay>().Where(wd => wd.Date >= @from && wd.Date <= to);
return query.ToListAsync().ConfigureAwait(false);

当执行这个语句时,实际上是在ToListAsync()方法而不是Where方法中断了。然而,这也没有帮助。

后来我尝试了下面的方法,它确实起作用了。

var result = await Connection.Table<WorkDay>().ToListAsync().ConfigureAwait(false);
return result.Where(wd => wd.Date >= @from && wd.Date <= to).ToList();

所以我实际上是将Where方法分离出来。但尽管这对我有效,它并没有回答我的问题,因为我仍然想知道为什么这样做不起作用。


“在where子句中的NRE是什么意思?”如果它实际上被编译成表达式树并作为这样处理,那么lambda本身不应该能够抛出异常,只有处理它的代码才能。你是否在“ToListAsync”被调用之前就已经收到了异常,或者你只是指“如果我删除Where,就没有异常”? - Matti Virkkunen
@MPelletier 是的。我使用调试器检查了一下,from 和 to 都有值。from 带有 @,因为它也是 C# 中的关键字,因此通常不允许使用该名称的变量。 - Stephan
@MattiVirkkunen 没错。当我移除Where()方法时,一切都正常工作。我现在也添加了堆栈跟踪。你可以看到它在CompileExpr中失败,我倾向于认为这是指Where表达式。也许有更好的方法来查看这个错误? - Stephan
你的表中有空日期吗? - MPelletier
@MPelletier 不是这样的。我通过使用 ISETool 从 Windows Phone 模拟器下载数据库,并使用 SQLite Administrator 查看表格来检查了这一点。所有条目(仅为一些测试条目)都有分配日期。那里没有空值。 - Stephan
显示剩余3条评论
3个回答

2
我很确定你已经不再参与这个项目了,但我还是会回答它,因为它可能会帮助仍在为此问题而苦苦挣扎的人。
问题出在你的实体上,我不知道具体问题是什么,因为你没有在这里发布你的类。但基本上,你可能正在尝试访问尚未从数据库中获取的属性。例如,我有一个带有两个属性的类:
"最初的回答"
public class MyClass
{
      public DateTime Date { get; set; } // You're saving this property in the database
      public bool IsLate => Date < DateTime.Today; // This property is not be saving, and probably is the cause of your exception
}

我不知道为什么SQLite会这样做,但当它查询您的实体时,如果在查询中按< strong> IsLate 属性进行过滤,则会崩溃,因为 Date 属性尚未获取。
要解决此问题,您需要首先获取实体,然后按此属性进行过滤。这基本上就是您在< strong> EDIT 2 中所做的事情。您已获取所有实体,然后进行了过滤。

我之前也遇到了同样的问题,而且就像你建议的那样解决了。 不过,我想着不是将值转换为列表然后在其上运行查询,而是这样做:query.AsEnumerable().Where(....) 因为 IEnumerable 是惰性求值的,所以不需要获取整个表。我的假设正确吗? - Arina
1
我不确定这是否能解决你的问题,因为我认为SQLite的工作方式与Entity Framework不同。你可以使用EF是因为DbContext实现了IQueryable,但在SQLite中并非如此。 - Daniel Cunha

1
也许我太新了不知道我在说什么,但我认为你最后的示例只需要在ToListAsync调用之前加上一个await语句即可。
var query = Connection.Table<WorkDay>().Where(wd => wd.Date >= @from && wd.Date <= to);
return await query.ToListAsync().ConfigureAwait(false);

我不确定第一个问题的具体情况,但我认为它与TableAsyncQuery对象有关,Where语句产生的对象在另一个线程上调用ToListAsync之前没有完全初始化。


很不幸,我现在使用的是另一个数据库(iBoxDB),所以无法再测试这个了。但我非常确定如果我尝试在没有异步的情况下访问任务结果,Visual Studio 会抱怨的。但我可能错了。 - Stephan

0

在Daniel Cunha的回答上添加更多细节 我在我的cProduct类中有这个

    [PrimaryKey, AutoIncrement]
    public int rowid
    {
        get => _rowid;
        set => _rowid = value;
    }

    [Ignore]
    public int ID => rowid; // just for convinience

这个查询是有效的

product.Product = dbConnection.Table<cProduct>().Where(s => s.rowid == product.ProductID).FirstOrDefault();

但是这个会出现空引用异常

product.Product = dbConnection.Table<cProduct>().Where(s => s.ID == product.ProductID).FirstOrDefault();

s.ID不能在数据库查询中使用...表格中没有这样的字段。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接