CoreData with #FetchRequest (SwiftUI) and NSPredicate crashes if there is no data - core-data

I have a SwiftUI app where I am using #FetchRequest along with a predicate. Everything works fine as long as there is already some data.
However, when the app is first installed and the user tries to perform a search before entering any data, the app crashes with this error:
error: SQLCore dispatchRequest: exception handling request: <NSSQLFetchRequestContext: 0x60000188c380> , unimplemented SQL generation for predicate : (username CONTAINS[cd] "r") with userInfo of (null)
I believe the cause of the problem is that the column doesn't exist (because there is no data). What I'd like to do is pass nil for the predicate in the case where this is no data.
I understand how to use NSManagedObjectContext and count(for:) but the context isn't really made available via the #EnvironmentObject at the time I need to use it. Does anyone have any suggestions as to how to handle this. I don't see how a try-catch would work either.
Thanks.

Well, I do have a solution. Its not pretty, but it does work. Because the NSManagedObjectContext is being passed around via #Environment it isn't initialized when a SwiftUI View init is being run. So to get the context you can do:
if let context = (UIApplication.shared.delegate as? AppDelegate)?.persistentContainer.viewContext {
and make the call to get the count in there.

So I'm clueless sometimes. I did not read the error thoroughly since it happened in the context of something I was changing so I thought the problem was that. But no, that is not the problem.
The problem is that earlier in the day, I renamed a column from username to something else. But I forgot to change the NSPredicate.
So for the sake of anyone else using SwiftUI and #FetchRequest, if you do need to count the number of items, you will need to revert to NSFetchRequest to do it. Sorry for wasting anyone's time.

Related

How Can I Check For The Existence of a UUID

I am trying to check for the existence of a UUID as a primary key in my Django environment...and when it exists...my code works fine...But if it's not present I get a "" is not a Valid UUID...
Here's my code....
uuid_exists = Book.objects.filter(id=self.object.author_pk,is_active="True").first()
I've tried other variations of this with .exists() or .all()...but I keep getting the ['“” is not a valid UUID.'] error.
I did come up with a workaround....
if self.object.author_pk is not '':
book_exists = Book.objects.filter(id=self.object.author_pk,is_active="True").first()
context['author_exists'] = author_exists
Is this the best way to do this? I was hoping to be able to use a straight filter...without clarifying logic....But I've worked all afternoon and can't seem to come up with anything better. Thanks in advance for any feedback or comments.
I've had the same issue and this is what I have:
Wrapping it into try/except (in my case it's a View so it's supposed to return a Response object)
try:
object = Object.objects.get(id=object_id)
except Exception as e:
return Response(data={...}, status=status.HTTP_40...
It gets to the exception (4th line) but somehow sends '~your_id~' is not a valid UUID. text instead of proper data. Which might be enough in some cases.
This seems like an overlook, so might as well get a fix soon. I don't have enough time to investigate deeper, unfortunately.
So the solution I came up with is not ideal either but hopefully is a bit cleaner and faster than what you're using rn.
# Generate a list of possible object IDs (make use of filters in order to reduce the DB load)
possible_ids = [str(id) for id in Object.objects.filter(~ filters here ~).values_list('id', flat=True)]
# Return an error if ID is not valid
if ~your_id~ not in possible_ids:
return Response(data={"error": "Database destruction sequence initialized!"}, status=status.HTTP_401_UNAUTHORIZED)
# Keep working with the object
object = Objects.objects.get(id=object_id)

Making multiple NSUserActivity instances searchable

I'm planning to make some of my app content publicly indexable, and for that I am using NSUserActivity. From my experiments so far, I've discovered that apparently the only activity that appears in the search results is the last one to get becomeCurrent called on. Is there a way to make all my activities searchable?
The following code is on my appDelegate:
for (Shop* shop in shopManager)
{
NSUserActivity* activity = [[NSUserActivity alloc] initWithActivityType:ACTIVITY_OPEN_SHOP];
activity.userInfo = #{#"additional1": shop.name};
activity.eligibleForPublicIndexing = YES;
activity.eligibleForSearch = YES;
activity.keywords = shop.indexableKeywords;
CSSearchableItemAttributeSet* attributeSet = [[CSSearchableItemAttributeSet alloc] initWithItemContentType:(NSString*)kUTTypeText];
attributeSet.title = shop.name;
attributeSet.contentDescription = shop.indexableDescription;
attributeSet.keywords = [shop.indexableKeywords allObjects];
[activity setContentAttributeSet:attributeSet];
[activity becomeCurrent];
[activities addObject:activity];
}
self.userActivities = [[NSSet alloc] initWithArray:activities];
Hey I have code that is very similar to yours and spotlight is able to index all of my NSUserActivity objects. My guess is that your NSUserActivity objects go out of reference as soon as the next iteration of the loop occurs. Try adding a strong property.
From this source on Apple Forums:
https://forums.developer.apple.com/message/13640#13640
In my case, I had code that was allocating the NSUA, setting some
properties on it, calling becomeCurrent, but then the object would go
out of scope and deallocated. If you're doing this, try tossing the
activity into a strong property to see if you can then see the results
when you search.
Let me know if it still doesn't work.
RequiredUserInfoKeys is the property of NSUserActivity that you have to set in order to work properly in search results.
activity.requiredUserInfoKeys = [NSSet setWithArray:#[#"additional1"]];
I have met the same problem. I think the reason of this is that previous user activity has not enough time for indexing its metadata by system, the next user activity have became current user activity, so only last one is searchable.
My solution is put latter one into a dispatch_after block and delay 1.5 second, making each of them has time to be indexed.
If someone has a better solution, I would be grateful.

Sitecore 7 Search, cannot access a disposed object

I've been working with some Sitecore 7 search code. Example below.
using (var context = Index.CreateSearchContext())
{
// ....Build predicates
var query = context.GetQueryable<SearchResultItem>().Where(predicate);
return query.GetResults();
}
This works fine in SOLR, but when used with standard Lucene, whenever I reference a property in the SearchResults<SearchResultItem> returned by GetResults(), Sitecore errors with "Cannot access a disposed object". It appears that GetResults() doesn't enumerate and still hangs on to the searchcontext.
Anyone come across this before and know how to fix? I've seen some articles suggesting having the SearchContext in application state, but ideally I want to avoid this.
Thanks
Ian
It seems that SearchResults<T> holds reference to SearchHit and the LuceneSearchProvider doesn't hold a reader open. The new version of Lucene automatically closes the reader. I think you might be returning the wrong type. You should probably do like this:
var query = context.GetQueryable<SearchResultItem>().Where(predicate);
return query.ToList();
However make sure, that don't return too many. You should probably use take() etc.
Is GetResults() returning a List or IEnumerable/IQueryable?
Try to return a list in case it isn't already.
return query.GetResults().ToList();
Cheers

How do you correctly update a model in Xcode4 without corrupting it?

I never had any problems with Xcode3, but with Xcode4 I'm getting Apple's code failing approx 1 time in 3 when I update a core data model, with the dreaded "Persistent store migration failed, missing source managed object model." error.
Here's my setup (how I configured the project to auto-migrate):
NSPersistentDocument, from Apple's template
Override Apple's model-loading method, and the ONLY thing I do is to provide the two flags in the storeOptions Dictionary, which turn on auto-migration
-(BOOL)configurePersistentStoreCoordinatorForURL:(NSURL *)url ofType:(NSString *)fileType modelConfiguration:(NSString *)configuration storeOptions:(NSDictionary *)storeOptions error:(NSError **)error
{
NSMutableDictionary *newOptions = nil;
if( storeOptions != nil )
newOptions = [NSMutableDictionary dictionaryWithDictionary:storeOptions];
else
newOptions = [NSMutableDictionary dictionary];
[newOptions setValue:#"YES" forKey:NSMigratePersistentStoresAutomaticallyOption];
[newOptions setValue:#"TRUE" forKey:NSInferMappingModelAutomaticallyOption];
BOOL success = FALSE;
success = [super configurePersistentStoreCoordinatorForURL:url ofType:fileType modelConfiguration:configuration storeOptions:newOptions error:error];
return success;
}
Here's the process I've been using (which is already working around 1 bug in Xcode4!)
Select the model (named "something.xcdatamodel" in Xcode4, with a twisty on the left)
Go to Editor menu, select "Add new model version..."
Name the new version 1 integer higher than last - e.g. if previous was "4" name the new one "5"
In the right-hand pane, change the current model version to the newly-created one
workaround for XCode4 bug: select any file, then select the newly-created model. If you do not, Xcode shows the selection on the newly-created model, but will edit the previous model instead, which definitely corrupts everything in CoreData
Edit your model; in this case, I'm adding a new attribute to an existing entity
Save. Build. Run. ... CRASH.
Except, as I said, approx 2 times in 3 this works correctly. Once it works once, it's (obviously) fine - the lightweight migration is complete, the next save saves in the new model version.
So I'm guessing there's something I'm doing wrong in the above steps, but I've been through the docs 5 or 6 times and can't see anything obvious. Doesn't help that NSPersistentDocument docs are all out of date - but I've done lightweight migration on iPhone lots of times too, so I'm reasonably confident with doing this, and it seems right to me.
Other things I've tried/checked:
- iPhone Core Data Lightweight Migration Cocoa error 134130: Can't find model for source store (nope; only the root xcdatamodel was being included)
Use [NSNumber numberWithBool:YES] not #"YES" or #"TRUE".
Since you have eliminated a corrupt development store as a source of the problem, I suspect the problem lays in Xcode 4.x which is buggy to say the least. A lot of people are reporting similar issues but no two problems seem exactly the same. It is probably a bug/s that only occur with specific data model setups so the problem will be very hard to track down.
You may simply have to abandon automatic migration and create an explicit migration map. It takes longer and introduces complexity into your code but it will always work.
If you have a shipping app and will be dealing with end user data in the wild, you do have a moral and business obligation to take the extra step to protect end user data.
I was getting super-confused but this, and it WASN'T working.. because I was assuming that the method would already HAVE a "store options" dictionary.. I just needed to check for it's existence before i set the aforementioned options…
-(BOOL)configurePersistentStoreCoordinatorForURL: (NSURL*)u
ofType: (NSString*)t
modelConfiguration: (NSString*)c
storeOptions:(NSDictionary*)o
error: (NSError**)e
{
return [super configurePersistentStoreCoordinatorForURL:u
ofType:t
modelConfiguration:c
storeOptions:
o ? [o dictionaryWithValuesForKeys:
#[ NSMigratePersistentStoresAutomaticallyOption, #YES,
NSInferMappingModelAutomaticallyOption, #YES]]
: #{ NSMigratePersistentStoresAutomaticallyOption :#YES,
NSInferMappingModelAutomaticallyOption :#YES}
error:e];
}

Subsonic BatchQuery.Queue causing 'Can't decide which property to consider the key...' exception

I'm just getting started with Subsonic 3.0 ActiveRecord and am trying to implement a batch query like the one in the SubSonic docs. I'm using a batch so I can query a User and a list of the users Orders in one shot.
When I call the BatchQuery.Queue() method, adding my "select user" query, SubSonic throws the following exception:
System.InvalidOperationException : Can't decide which property to consider the Key - you can create one called 'ID' or mark one with SubSonicPrimaryKey attribute
The code is as follows:
var db = new MyDB();
var userQuery = from u in db.Users //gets user by uid
where u.uid == 1
select u;
var provider = ProviderFactory.GetProvider();
var batch = new BatchQuery(provider);
batch.Queue(userQuery); //exception here
//create and add "select users orders" query here...
First things first - Why this error? My SubSonic Users object knows it's PK. "uid" is the PK in the database and the generated code reflects this. And I thought SubSonicPrimaryKey attribute was for the SimpleRepository? Is this way of batching not for ActiveRecord?
I could ask a number of other questions, but I'll leave it at that. If anyone can help me figure out what is going on and how to issue 2 batched queries I'd be grateful!
Edit - after further investigation
I ran through the source code with the debugger. Adam is correct - the ToSchemaTable() method in Objects.cs is apparently building out my schema and failing to find a PK. At the very end, it tries to find a column property named "ID" and flags this as the PK, otherwise it throws the exception. I added a check for "UID" and this works!
Still... I'm confused. I'm admittedly a bit lost after peeling back layer after layer of the source, but it seems like this portion of code is trying to build up a schema for my table and completely ignoring my generated User class - which quite nicely identifies which column/property is the PK! It doesn't seem quite right that I'd be required to name all keys "ID" w/ ActiveRecord.
I think the answer you're looking for is that this is a really stupid bug on my part. I'm hoping to push another build next week and if you could put this on the issue list I'd really appreciate it. My apologies...
SubSonic expects your primary key to be called Id so it's getting confused. SubSonicPrimaryKey is for simple repository but I assume where that exception is being thrown is shared between the different templates. If you rename your PK to Id or id or ID your query will work.

Resources