Question

I have an expression that's unwilling to get processed by LINQ in SQLITE.

Using SQLLite 3.8.3.1 Using SQLite-net 2.1

The expression is:

int stars = location.MinRating;
bool onlyLargePhotos = location.OnlyLargePhotos;

var query = db.MediaItems.Where(x => x.LocationId == location.LocationId && x.Rating >= stars && (!onlyLargePhotos || (onlyLargePhotos && (x.Width >= 2000 || x.Height >= 2000))));

This query, when accessed, fails. It seems like it's tripping on !onlyLargePhotos.

The exception is:

System.NotSupportedException occurred
  HResult=-2146233067
  Message=Cannot compile: Not
  Source=SQLite.Net
  StackTrace:
       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.Count()
       at SmartFrame.Mosh.DB.WeightedLocationHelper.<>c__DisplayClass9.<CalculateWeightsAsync>b__2(IndexConnection db)
  InnerException: 

Also - can anyone tell me if there's a way to see what SQL a query is going to execute? In SQL LINQ, the ToString() of an IQueryable will show you what's about to be executed.

(BTW: I know I can work around this by creating two different LINQ expressions.. However, I am going to have more permutations - more fields I am going to check - and as such, I don't want to have 8-16 queries I need to maintain - I want the work to be done by the SQL engine)

Was it helpful?

Solution

The .net SQLite wrapper is not perfect and lacks from many methods and functions. Especially the Where clause. It is not able to compile some expressions, so try to write them simpler as you can. For that, try the following:

var query = db.MediaItems.Where(x => x.LocationId == location.LocationId && x.Rating >= stars && (onlyLargePhotos == false || (onlyLargePhotos == true && (x.Width >= 2000 || x.Height >= 2000))));

BTW, why do you need to put the variable 'onlyLargePhotos' inside the where? It is not a variable and then the query could be divided. Just split your where in 2 wheres. Don't worry about the performance, both where's will be activated only on demand and not separately, something like that:

Func<MediaItem, bool> func;
if (onlyLargePhotos)
{
    func = ((x => x.LocationId == location.LocationId && x.Rating >= stars) && ((x.Width >= 2000 || x.Height >= 2000)));
}
else
{
    func = (x => x.LocationId == location.LocationId && x.Rating >= stars);
}

var query = db.MediaItems.Where(func) 

Regarding the SQL generated, you can't see it.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top