简体   繁体   中英

SQLite.net table query throws NullReferenceException

I'm using the following line of code to query some data from a given table in a SQLite database (platform is WP81 but I guess this doesn't matter here).

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

When I execute my code I get a NullReferenceException in the Where clause. When I remove the where condition everything works fine.

return await Connection.Table<WorkDay>().ToListAsync().ConfigureAwait(false);

In order to make sure that all entries in my table are valid and there is no null value in the Date column I used an SQL tool to look into the SQLite database.

As I can't debug lambda expressions I'm kind of stuck on how to find the issue here. My assumption is that something goes wrong due to the async handling.

Edit: Here is the exact stacktrace of the exception

{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)}

Edit 2:

I played around a bit more and figured out the following.

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

When executing this statement it actually breaks in the ToListAsync() method instead of the Where method. However, this doesn't help either.

Later I tried the following which actually works.

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

So what I did is to separate the Where method actually. But although this works for me it does not answer my question because I'm still wondering why this does not work.

I'm pretty sure you are not working in this project anymore, but I'm going to answer it because it may help someone which still is struggling with this problem.

The problem is your entity and I don't know what exactly is the problem because you didn't post your class here. But basically you probably were trying to access a property that wasn't fetch from your database yet. For example, I have a class with two properties:

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
}

I don't know why SQLite does that, but when it is querying your entities, if in your query you're filtering by IsLate property, it's going to crash because Date property wasn't fetch yet.

For solving this you'll have to fetch the entities first, then filter by this property. That's basically what you did in EDIT 2 . You've fetch all entities then filtered.

Maybe I am too new to know what I am talking about, but I think your last example just needed an await statement before your ToListAsync call.

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

Not sure on the specifics of the first problem, but I would think that it has something to do with the TableAsyncQuery object, that the Where statement produces, not being fully initialized before the ToListAsync calls it on another thread.

adding bit more details to Daniel Cunha answer i have this in my cProduct class

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

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

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

but this fails with null reference exception

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

s.ID can't be use in db query.. there is not such field in the table.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM