NSPredicate: More AND condition after ANY is possible? - nspredicate

[NSPredicate predicateWithFormat:#"ANY (spaceVariableDomains.domain.name = %# AND spaceVariableDomains.variable.val = %#)", ...];
I want to write something like above into NSPredicate, but it is unable to parse the format string. Is it possible somehow compound conditions after ANY? Do I need to use SUBQUERY?

Finally I used SUBQUERY approach, basically this expression helped me:
SUBQUERY(spaceVariableDomains, $x, $x.domain.name = 'xxx' and $x.variable.val = 'yyy').#count > 0 AND SUBQUERY(spaceVariableDomains, $x, $x.domain.name = 'zzz' and $x.variable.val = 'www').#count > 0

Related

Collection operator for summing a NSDictionary's values

Is there a simple way using KVO and collection operators, that I can sum the total value of a NSDictionary like { ID: NSNumber }?
Example:
#{
"my_ID_abcd": #(8),
"my_ID_efgh": #(2),
"my_ID_ijkl": #(3)
}
Would give 13 as a result.
Indeed #count doesn't return what I want, and #sum doesn't work here.. allValues.#sum.self neither...
I need to check the sum in a NSPredicate...
Thanks!
A way to do that would be to use a SUBQUERY(,,) & FUNCTION(,):
NSDictionary *dict = #{ #"my_ID_abcd": #(8),
#"my_ID_efgh": #(2),
#"my_ID_ijkl": #(3)};
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SUBQUERY(FUNCTION(SELF, 'allValues'), $idsValues, $idsValues = $idsValues).#sum.integerValue = %d", value];
BOOL pass = [predicate evaluateWithObject:dict];
From what I tried, you can't really chain two operators (ie #sum & #allValues, so I used a SUBQUERY:
SUBQUERY(allValues, $idsAllValues, $idsAllValues = $idsAllValues)
Since, you need a "true/false" on the last one, I used a simple comparaison against itself.
And I used FUNCTION to build the array of values.
That way, in the end, I can call #sum on it.
I'm not very familiar with SUBQUERY & FUNCTION, maybe the call could be simplified.
If you could use predicateWithBlock:, it would be much simpler though:
NSPredicate *withBlock = [NSPredicate predicateWithBlock:^BOOL(id _Nullable evaluatedObject, NSDictionary<NSString *,id> * _Nullable bindings) {
NSInteger sum = [[[evaluatedObject allValues] valueForKeyPath:#"#sum.self"] integerValue];
return sum == value;
}];

why is this not possible in doctrine

I have to do some queries, while i was trying different ways, i found out that the next lines are not "recognized" by doctrine (it gives errors):
for example, when i want to compare if some data in the db is equal to a literal, here the condition:
('u.gender = M')
this is how my table look like:
id gender
1 M
2 M
3 F
it throws a semantical error. Also when comparing dates that way.
I would like to know why this is not recognized by doctrine, while comparing directly with numbers is accepted:
condition: ('u.age = 15')
First option you can do this way-
$M = 'M';
$age = 15;
$query = $this->createQueryBuilder('t')
->where('u.gender = :M AND u.age = :age')
->setParameters(array('M'=> $M,'age'=>$age);
another way to do this-
$query = $this->createQueryBuilder("t")
->where("u.gender = 'M' AND u.age = 15");
So i guess the answer to my question would be that it was not working because doctrine didn't recognize M as a string. That is why it was necessary to use inverted commas like #Mehedi said.
Another way of solving this was to use the query builder:
$v = 'M';
$condition = $this->qb->expr()->eq('u.gender', $this->qb->expr()->literal($v));
but i guess that is just long and hard to read. So the shortest thing would be just:
$condition = ("u.gender = 'M'");

NSPredicate with Multiple parameters

Hello Need help with predicate. The problem is that I want to have one function which will fetch from database depends on the multiple values it receives, but the values don't always exist, does it mean I have to create several different predicates?
Code below
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"brand_id LIKE %# AND brand_id LIKE %# AND brand_id LIKE %# AND brand_id LIKE %# AND brand_id LIKE %# AND item_category LIKE %# AND item_make LIKE %# AND item_gender LIKE %# || item_price>%# || item_price<%#",
brand_one, brand_two, brand_three, brand_four, brand_five, categoryString, makeString, genderString,[NSNumber numberWithInt:price_bottom],[NSNumber numberWithInt:price_top]];
brand_one, brand_two and etc sometimes exist and sometimes don't.
And how should it for item_gender for example. Let's if there is no gender specified than to have both of them.
Sorry if my description of the problem confusing.
Base on Gobras comments the following code was produces
NSArray *brands = [NSArray arrayWithObjects:brand_one, brand_two, brand_three, brand_four, brand_five, nil];
NSPredicate *predicate_brands = [NSPredicate predicateWithFormat:#"brand_id like %#" argumentArray:brands];
Logical explanation of what what search function should
fetchrequest
predicate on fetch request
predicate based on 5 brand ids, item id, item category, item make, item gender,
if any of above is empty it should fetch all related entries for example if item category is empty it should fetch all "Jewellery, Watches and etc" but limit it with the rest of the predicate expressions.
Should I create for example compound predicates for brands and than create another one for item category with values "item_category like Jewellery" and "item_category like Watches" and after that how do I exactly bring them together?
Assemble an appropriate collection of individual predicates into NSCompoundPredicate
as in
NSMutableArray *parr = [NSMutableArray array];
if([brand_one length]) {
[parr addObject:[NSPredicate predicateWithFormat:#"brand_id LIKE %#",myBrandId]];
}
if([brand_two length]) {
// etc
}
NSPredicate *compoundpred = [NSCompoundPredicate andPredicateWithSubpredicates:parr];
You can stack up your predicates with orPredicateWithSubpredicates: and andPredicateWithSubpredicates: and NSCompoundPredicate being a NSPredicate itself can be compounded.
See
https://developer.apple.com/documentation/foundation/nscompoundpredicate
For those who are interested in Swift!
let arrPred = [NSPredicate(format: "yourAttribute LIKE %#", toCompareID), NSPredicate(format: "yourAttribute2 LIKE %#", toCompareID2)] //Add as many predicates you want in short make your query
let compoundpred:NSPredicate = NSCompoundPredicate(andPredicateWithSubpredicates: arrPred)
var arrFiltered = yourArray.filteredArrayUsingPredicate(compoundpred)
It's pretty simple to build the predicate dynamically: combine your predicate format string with desired number of conditions and build corresponding NSMutableArray with the arguments. [NSPredicate predicateWithFormat:argumentArray:] will do the rest.

'And' operator in Linq

I have a query that prints userid in label1 when username is entered.Works fine; but i want to write query for username and password that prints userid. so how can i write it? i tried writing using 'and' operator but dont seems to work.
int id = (from auser in lq.logins
where auser.username == userNameString //&& auser.Password =pwdString
select auser.userid).SingleOrDefault();
label1.Text = id.ToString();
Thanks
Ani
It looks like you used the assignment operator = instead of the comparison operator ==. The query should be:
int id = (from auser in lq.logins
where auser.username == userNameString && auser.Password == pwdString
select auser.userid).SingleOrDefault();
label1.Text = id.ToString();
It probably doesn't work becase you used = instead of ==.

Linq expression subsonic 3.0.0.3

I want to 'build' a combined query for Subsonic 3.0.0.3, what is the best way for this?
I tried;
Expression<Func<Person, bool>> exp = p => true;
Expression<Func<Person, bool>> fContinent = p => p.ContinentID == 1;
Expression<Func<Person, bool>> fType = p => p.TypeID == 1;
exp = Expression.Lambda<Func<Person, bool>>(Expression.AndAlso(exp, fContinent), exp.Parameters);
exp = Expression.Lambda<Func<Person, bool>>(Expression.AndAlso(exp, fType), exp.Parameters);
var personList = Person.Find(exp);
But that will give the exception "The binary operator AndAlso is not defined ..."
I also tried using predicates but that will throw exceptions as well (Expression.Invoke is not supported).
In subsonic 2 I would have used the SqlQuery object, but I would like to know the proper way to do this in version 3 using linq / expressions.
Have you tried And instead of AndAlso?
The right way to do this is to combine the lambda expression bodies, like this:
exp = Expression.Lambda<Func<Person, bool>>(
Expression.And(exp.Body, fContinent.Body), exp.Parameters);
Even if And is supported by your query provider, you'll also need to replace the parameter references in fContinent's Body with references to the parameter defined in exp--as is, your two expression bodies (combined with And) reference two distinct parameters, each named p.
See my answer to this question for the cleanest method to replace expression parameters.
I asked this question, but I am using the combined query in subsonic just like you.
In short, you want to use a PredicateBuilder to build up the query. When you want to execute it in your subsonic object (assuming ActiveRecord), use code like this:
var predicate = /* Build up predicate with PredicateBuilder */;
var recs = SubsonicClass.All().Where(predicate.Compile()).ToList();

Resources