CloudKit Query: After Date and Not in Array - nspredicate

I'm trying to query records from CloudKit that either have a newer modificationDate than what I have locally, or perhaps that I don't have at all.
The records I have already are stored in recordNames. The the date is date.
I can do this with two predicates like this:
//Modification Date
let predicateDate = NSPredicate(format: "modificationDate > %#", date)
//Records I have already
let predicateRecordName = NSPredicate(format: "NOT (recordName IN %#)",recordNames)
//Combined 'OR'
let predicate = NSCompoundPredicate(orPredicateWithSubpredicates: [predicateDate, predicateRecordName])
But when I try to combine this as a compound OR predicate, or combine them into a single predicate, I get an error:
Invalid predicate... CKErrorDomain Code=12... is not a comparison predicate, ck_isComparisonError=true
I see in the docs that doing an OR predicate is not allowed. I'd love to not have to make two separate queries here. Any ideas on how I can pull this off?

'OR' option not working with predicates (I don't know if this is a bug of CloudKit). You have to make multiple queries.

Related

LINQ query to find items where multiple substrings are searched on one column

Select * from web_data where Title like "%Lawn%" || Title like "%silk%"......and so on.
Lawn, Silk etc are in List<web_data>. So i'm looking for a way to search those substrings in the Title column(discription property). One of them must be contained, then the row should be returned.
I've tried this
query = query
.Where(x => filter.FabricType.Any(f => x.discription.Contains(x.discription)))
.AsQueryable();
It's not working. That linq to sql code returns an error:
Local sequence cannot be used in LINQ to SQL implementations of query operators except the Contains operator.
any alternatives?
You can use Contains() or You can also use .StartsWith() or .EndsWith().
collListItem.Where(x => x.discription.Contains("Lawn") || x.discription.Contains("silk")).ToList();

How do I filter in linq query when field needs parsing first?

I have a data table containing multiple columns and one column that stores somewhat complex text patterns - I need to parse the field to determine if a particular sub strings exist in specific positions within the larger string pattern and then if the record should be filtered out as a result.
I can't see a way to perform the parse other than by writing a C# parsing function with String.Split method calls, foreach, etc. But if I try to parse like this:
var myFilteredTable = _db.MyTable.Where(t => t.Column1 == 'Filter1'
&& ParseIsMyItemInColumn2(t) );
I get "has no supported translation to SQL" errors.
The other option I thought of was to build the initial result without the Parse:
var myFilteredTable = _db.MyTable.Where(t => t.Column1 == 'Filter1' );
and iterate through the IQueryable resultset, testing each row with the parse function, to filter out the unwanted rows, but IQueryable does not have Remove function to strip out unwanted rows nor Add function to allow me to build up a new resultset.
So how can I filter in linq when I also need to write a Parse function?
Well the "initial filter in the database then do the rest locally" is easy:
var filtered = _db.MyTable.Where(t => t.Column1 == "Filter1")
.AsEnumerable() // Do the rest locally
.Where(t => ParseIsMyItemInColumn2(t));
AsEnumerable is a simple pass through method, but because the result is typed as IEnumerable<T> rather than IQueryable<T>, the subsequent LINQ operations use the LINQ to Objects methods in Enumerable rather than the ones in Queryable.
Obviously if a lot of items match the first filter but fail the second, that won't be terribly efficient...
Unfortunately, if the "parse function" is not something that can be translated to SQL, you will need to pull the results and use LINQ to Objects:
var myFilteredTable = _db.MyTable.Where(t => t.Column1 == 'Filter1')
.AsEnumerable().Where(ParseIsMyItemInColumn2);
Note that this will stream all of the results into memory, and then perform your parse.

Core data to-many NSPredicate with AND

I'm trying to write a query for the find-as-you-type search bar. What I want to do is query "Kind", and return any Kinds for which there is a LocalName with ('name' LIKE %# AND localeIdentifier == %#).
If I'm only searching the names (so ignoring the localeIdentifier), I could do something like this:
ANY localized.name LIKE %#
What I want is something more like
ANY localized.(name LIKE %# AND localeIdentifier == %#)
To sum up, searching "Kind", any one item in the to-many relationship "localized" should match both name and localeIdentifier.
Any ideas for the correct syntax of this?
What you want is a subquery. In predicate format syntax:
SUBQUERY(self.localized, $x, $x.name LIKE %# AND $x.localeIdentifier == %#).#count > 0
where the SUBQUERY expression returns a collection of instances in the self.localized collection that match the predicate in the third argument. Kind instances for which this SUBQUERY expression is non-empty (ie #count > 0) match your desired criteria.
The SUBQUERY expression was introduced in OS X 10.5.

LINQ syntax where string value is not null or empty

I'm trying to do a query like so...
query.Where(x => !string.IsNullOrEmpty(x.PropertyName));
but it fails...
so for now I have implemented the following, which works...
query.Where(x => (x.PropertyName ?? string.Empty) != string.Empty);
is there a better (more native?) way that LINQ handles this?
EDIT
apologize! didn't include the provider... This is using LINQ to SQL
http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=367077
Problem Statement
It's possible to write LINQ to SQL that gets all rows that have either null or an empty string in a given field, but it's not possible to use string.IsNullOrEmpty to do it, even though many other string methods map to LINQ to SQL.
Proposed Solution
Allow string.IsNullOrEmpty in a LINQ to SQL where clause so that these two queries have the same result:
var fieldNullOrEmpty =
from item in db.SomeTable
where item.SomeField == null || item.SomeField.Equals(string.Empty)
select item;
var fieldNullOrEmpty2 =
from item in db.SomeTable
where string.IsNullOrEmpty(item.SomeField)
select item;
Other Reading:
1. DevArt
2. Dervalp.com
3. StackOverflow Post
This won't fail on Linq2Objects, but it will fail for Linq2SQL, so I am assuming that you are talking about the SQL provider or something similar.
The reason has to do with the way that the SQL provider handles your lambda expression. It doesn't take it as a function Func<P,T>, but an expression Expression<Func<P,T>>. It takes that expression tree and translates it so an actual SQL statement, which it sends off to the server.
The translator knows how to handle basic operators, but it doesn't know how to handle methods on objects. It doesn't know that IsNullOrEmpty(x) translates to return x == null || x == string.empty. That has to be done explicitly for the translation to SQL to take place.
This will work fine with Linq to Objects. However, some LINQ providers have difficulty running CLR methods as part of the query. This is expecially true of some database providers.
The problem is that the DB providers try to move and compile the LINQ query as a database query, to prevent pulling all of the objects across the wire. This is a good thing, but does occasionally restrict the flexibility in your predicates.
Unfortunately, without checking the provider documentation, it's difficult to always know exactly what will or will not be supported directly in the provider. It looks like your provider allows comparisons, but not the string check. I'd guess that, in your case, this is probably about as good of an approach as you can get. (It's really not that different from the IsNullOrEmpty check, other than creating the "string.Empty" instance for comparison, but that's minor.)
... 12 years ago :) But still, some one may found it helpful:
Often it is good to check white spaces too
query.Where(x => !string.IsNullOrWhiteSpace(x.PropertyName));
it will converted to sql as:
WHERE [x].[PropertyName] IS NOT NULL AND ((LTRIM(RTRIM([x].[PropertyName])) <> N'') OR [x].[PropertyName] IS NULL)
or other way:
query.Where(x => string.Compare(x.PropertyName," ") > 0);
will be converted to sql as:
WHERE [x].[PropertyName] > N' '
If you want to go change the type of the collection from nullable type IEnumerable<T?> to non-null type IEnumerable<T> you can use .OfType<T>().
.OfType<T>() will remove null values and return a list of the type T.
Example: If you have a list of nullable strings: List<string?> you can change the type of the list to string by using OfType<string() as in the below example:
List<string?> nullableStrings = new List<string?> { "test1", null, "test2" };
List<string> strings = nullableStrings.OfType<string>().ToList();
// strings now only contains { "test1", "test2" }
This will result in a list of strings only containing test1 and test2.

Entity Framework - "Unable to create a constant value of type 'Closure type'..." error

Why do I get the error:
Unable to create a constant value of type 'Closure type'. Only
primitive types (for instance Int32, String and Guid) are supported in
this context.
When I try to enumerate the following Linq query?
IEnumerable<string> searchList = GetSearchList();
using (HREntities entities = new HREntities())
{
var myList = from person in entities.vSearchPeople
where upperSearchList.All( (person.FirstName + person.LastName) .Contains).ToList();
}
Update:
If I try the following just to try to isolate the problem, I get the same error:
where upperSearchList.All(arg => arg == arg)
So it looks like the problem is with the All method, right? Any suggestions?
It looks like you're trying to do the equivalent of a "WHERE...IN" condition. Check out How to write 'WHERE IN' style queries using LINQ to Entities for an example of how to do that type of query with LINQ to Entities.
Also, I think the error message is particularly unhelpful in this case because .Contains is not followed by parentheses, which causes the compiler to recognize the whole predicate as a lambda expression.
I've spent the last 6 months battling this limitation with EF 3.5 and while I'm not the smartest person in the world, I'm pretty sure I have something useful to offer on this topic.
The SQL generated by growing a 50 mile high tree of "OR style" expressions will result in a poor query execution plan. I'm dealing with a few million rows and the impact is substantial.
There is a little hack I found to do a SQL 'in' that helps if you are just looking for a bunch of entities by id:
private IEnumerable<Entity1> getByIds(IEnumerable<int> ids)
{
string idList = string.Join(",", ids.ToList().ConvertAll<string>(id => id.ToString()).ToArray());
return dbContext.Entity1.Where("it.pkIDColumn IN {" + idList + "}");
}
where pkIDColumn is your primary key id column name of your Entity1 table.
BUT KEEP READING!
This is fine, but it requires that I already have the ids of what I need to find. Sometimes I just want my expressions to reach into other relations and what I do have is criteria for those connected relations.
If I had more time I would try to represent this visually, but I don't so just study this sentence a moment: Consider a schema with a Person, GovernmentId, and GovernmentIdType tables. Andrew Tappert (Person) has two id cards (GovernmentId), one from Oregon (GovernmentIdType) and one from Washington (GovernmentIdType).
Now generate an edmx from it.
Now imagine you want to find all the people having a certain ID value, say 1234567.
This can be accomplished with a single database hit with this:
dbContext context = new dbContext();
string idValue = "1234567";
Expression<Func<Person,bool>> expr =
person => person.GovernmentID.Any(gid => gid.gi_value.Contains(idValue));
IEnumerable<Person> people = context.Person.AsQueryable().Where(expr);
Do you see the subquery here? The generated sql will use 'joins' instead of sub-queries, but the effect is the same. These days SQL server optimizes subqueries into joins under the covers anyway, but anyway...
The key to this working is the .Any inside the expression.
I have found the cause of the error (I am using Framework 4.5). The problem is, that EF a complex type, that is passed in the "Contains"-parameter, can not translate into an SQL query. EF can use in a SQL query only simple types such as int, string...
this.GetAll().Where(p => !assignedFunctions.Contains(p))
GetAll provides a list of objects with a complex type (for example: "Function"). So therefore, I would try here to receive an instance of this complex type in my SQL query, which naturally can not work!
If I can extract from my list, parameters which are suited to my search, I can use:
var idList = assignedFunctions.Select(f => f.FunctionId);
this.GetAll().Where(p => !idList.Contains(p.FunktionId))
Now EF no longer has the complex type "Function" to work, but eg with a simple type (long). And that works fine!
I got this error message when my array object used in the .All function is null
After I initialized the array object, (upperSearchList in your case), the error is gone
The error message was misleading in this case
where upperSearchList.All(arg => person.someproperty.StartsWith(arg)))

Resources