Say I have 3 string fields and I want to search for the same string inside those fields.
I need a way to make a dynamic OR because the fields may be more than 3, or less and the OR search must work consistently, thus I can't do the Where(Linq.Contains('Prop1',Value) or... or...) but it needs to be dynamic, so the ORs have to be appended one after another.
I can finally come back to this.
So, I followed what you said and now have a method which will gather up all the ORs and package them neatly in a TLinqExpression. So far, so good.
Now though I have to append or prepend this to my WHERE for the other criteria if I have any in a OR, because I may have a full text search but also filters, so this needs to be injected in the where that is built separately.
Any ideas of how to do this? There doesn't seem to be an underlying expression property that I can hook this up to.
It would be up to you to parse, analyze and check which has OR statement and which one you want to add. It's very complex imho. You should refactor your code to tell your full search text logic to which expression to add more conditions.
Oh it's not only possible, it's likely!
But to try to clarify what I am saying here:
the way I have done this means we have two "lumps": one lump is for filtering (Linq.GreaterOrEqual etc.) and another is the various Linq.Contains that constitute the full text search.
Thus, from a logical standpoint it's 2 expressions if you see what I mean.
So, I have finally gotten around to doing this and am having an issue.
My code looks like this:
// Other stuff here
LocalCriteria: TCriteria; // Criteria to swap in if there is a quick search
CriteriaIntf: IAureliusCriteria; // Interface allowing the swapping in
Expr: TLinqExpression; // Expression to put in OR
ExprIntf: IAureliusExpression; // Filter expression
FilterVal: IFilterRawValue; // Raw value for the filter
// Other stuff here
if Not QuickSearch.IsEmpty then
LocalCriteria := ObjectManager.Find<TORM>;
if Supports(ORM, IAureliusCriteria, CriteriaIntf) then
if CriteriaIntf.HasCriteria then
for var StrFilter in FStringFilters do
Filter := StrFilter.Create;
IAureliusCriteria( Filter ).SetCriteria(LocalCriteria); // Ensure the filter uses the right criteria.
ExprIntf := Filter as IAureliusExpression; // Extract the Aurelius Expression interface from the filter
Expr := Expr or ExprIntf.ExposeExpression; // OR the expression
FilterVal := Filter as IFilterRawValue; // Prepare to set the value
FilterVal.RawValue := QuickSearch; // Set the value
LocalCriteria.Where(Expr); // Add all to the where which is no (... OR... OR....etc.)
// More stuff here
QuickSearch is a string parameter. When I execute the whole thing, I get an AV with the following call stack:
Well, you have a lot of your own code there. You almost didn't show any pure Aurelius code, so I cannot tell what's going on. I'm afraid you will have to review your code or create a very minimum project reproducing the issue.
Note that the original code I sent you has an ExtractAt. You have to be careful about what you destroy, add and remove, because the manager and the criteria objects often destroy some objects automatically - manager destroys the criteria itself, and criteria destroys its expressions.
Yes, there is a ton of custom code, I agree, but basically all of it is syntactic sugar to do things more easily and uniformly: for example, IAureliusExpression has a method called ExposedExpression which exposes the internal LINQ expression. Filtering, likewise, works with an internal TCriteria and a List and so on. There is very little in terms of code that does something "complex" and in most cases the classes simply implement field or table names to get the LINQ expressions right. Wherever there are multiple options (such as date ranges, for example) what I do is branch out for the correct LINQ expression instead of trying to be fancy and doing something too weird. The other thing is that I am not using ExtractAt because, as you say, doing that sort of thing is quite dangerous. What I am doing instead is pre-process the quick search so that the whole thing becomes one big bracketed expression to which I then append the various implicit "ANDs" by using the fluent interface.
So basically what I think I am doing is this:
Calculate the quick search expression as a set of ORs:: this is one expression that gets added to the where as first thing
Then I add the other filters as required, based on an auto-name that is determined by the filter class and use the raw value to set the appropriate filter value
Therefore at the end of the whole thing and before calling the list, I have this situation:
Criteria.Where( A and B) where A is an expression of all the ORs in the quick search and should therefore be seen by Aurelius as a single bracketed expression.
I have further debugged the thing and realised that
procedure TOrExpression.Accept(Visitor: TCriterionVisitor);
Is the problem because Self in that point is nil, but this happens during the ORs and I cannot easily determine the actual flow. There are 7 string filters that are checked and when I go into the 7th Aurelius tries to do an OR and visit the internal tree but finds a NIL on the left side. Because of this, when it tries to visit it generates an AV.
Hard to tell. Looks like a complex code. I can't point what's going wrong, unfortunately. You wrote the code and you have access to all of it, and still you don't know what's going on.
So please create a minimal project reproducing the issue that we can run at our side here and then I can check what's going on. My simple guess is that you are mixing up the handling of objects lifetime. Each expression holds and destroys its own sub expression, so possibly you are doing something wrong in that part. But again, I can only guess.