Version
5.0.9
Code to Reproduce
For simplicity:
void Main()
{
var cs = new ConnectionString
{
Filename = @"c:\mydb.db",
Password = @"MyP@55w0rd"
};
using (var db = new LiteDatabase(cs))
{
var col = db.GetCollection<Product>("Prods");
col.Insert(new Product{ Name="AAA"});
col.Insert(new Product{ Name="AEE"});
var predicate = PredicateBuilder.False<Product>();
predicate = predicate.Or(p => p.Name.Contains("A"));
col.Find(predicate).Count().Dump(); //<== NotSupportedException
}
}
public class Product
{
public int Id{get;set;}
public string Name{get;set;}
}
Expected behavior
The Count method should return the number of documents
Stacktrace
at LiteDB.LinqExpressionVisitor.Resolve(Boolean predicate)聽聽
at LiteDB.BsonMapper.GetExpression[T,K](Expression`1 predicate)聽聽
at LiteDB.LiteCollection`1.Find(Expression`1 predicate, Int32 skip, Int32 limit)聽聽
at UserQuery.Main(), line 20
Exception Message
Invalid BsonExpression when converted from Linq expression: f => (False OrElse Invoke(p => p.Name.Contains("A"), f)) - `(((@p0) = true) OR @.Name LIKE ('%' + @p1 + '%')$)`
LiteException
Unexpected token `$` in position 49.
Any help would be greatly appreciated.
@toumir Yes, it is a bug. The resulting BsonExpression is slightly wrong, it is being created with an additional $ at the end, which makes it invalid. I'm going to investigate it, but you could simply use col.Find(p => p.Name.Contains("A")), dropping PredicateBuilder altogether.
Thank you @lbnascimento, like I said, the real query is very complex and I must use the PredicateBuilder to build it dynamically,
in LiteDB v4 I was able to use List<Query> and build my query, but not in v5, I get this Error :
cannot convert from 'LiteDB.BsonExpression' to 'LiteDB.Query'
this code not work any more in v5:
var queries = new List<Query>();
if(condition)
{
queries.Add(Query.EQ(nameof(Tiers.IsSpecial), isSpecial));
}
if(condition2)
{
queries.Add(Query.Or(Query.EQ(nameof(Tiers.Type), typeTiers), Query.EQ(nameof(Tiers.Type), 3)));
}
...
db.GetCollection<Tiers>(nameof(Tiers)).Count(queries.ToArray()); //use case
have you a best solution?
Thanks in advance
@toumir You could do something like this:
```C#
var col = db.GetCollection
...
var query = col.Query();
if(condition)
{
query.Where(x => x.Tiers.IsSpecial == isSpecial);
}
if(condition2)
{
query.Where(x => x.Tiers.Type == typeTiers || x.Tiers.Type == 3);
}
var count = query.Count();
```
FYI : For completeness, build and pass predicate to Collection / Query method, even without using PredicateBuilder lead to the same error :
Expression<Func<Product,bool>> predicate = p=>true;
predicate = predicate.And(p => p.Name.Contains("F"));
col.Count(predicate); //Exception
var qry = col.Query();
qry.Where(predicate).Count();//Exception
@toumir This issue has been fixed in the master and its fix will be present in the next incremental release. In the meantime, I suggest you use the ILiteQueryable<T> interface from col.Query(), for which I gave an example in my previous comment.
Still can't execute Find/Count with dynamically built predicates,
LiteDB version master branch with the fixed bug above,
Let say I have two methods that return a predicates:
var predicate1 = t=>true;var predicate2 = t=>trueAfter combining the two results : var result = predicate1.And(predicate2); and call the find method
col.Find(result);
I get this error:
Expression '@p1' are not supported as predicate expression.
Can someone help
@lbnascimento Any chances getting a snapshot version or a 5.0.10 including the fix? Unfortunately, I have the same issue.
@lbnascimento waiting for the next release, what I'm doing, I cloned the repository, compiled it at my level and referenced the dll
I'm also looking for a fix for this. I have so very much code using PredicateBuilder that I really don't want to rewrite, plus I am unsure how I can substitute col.Query() for every single instance (queries with dynamic and complex and's and or's, using predicates with DeleteMany(), etc.).
@lbnascimento Am I missing some documentation page on how to use Query()? I can't find anything.
Most helpful comment
@toumir This issue has been fixed in the master and its fix will be present in the next incremental release. In the meantime, I suggest you use the
ILiteQueryable<T>interface fromcol.Query(), for which I gave an example in my previous comment.