Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fetchAll returning empty array #449

Open
darrenasaro opened this issue Mar 17, 2022 · 10 comments
Open

fetchAll returning empty array #449

darrenasaro opened this issue Mar 17, 2022 · 10 comments

Comments

@darrenasaro
Copy link

I have an app which stores an entity class EntityA: NSManagedObject {...}
I have the following simplified CoreData code to fetch this entity

    let container = NSPersistentContainer(name: "Model")
    let context = container.viewContext
    let coordinator = NSPersistentStoreCoordinator(managedObjectModel: container.managedObjectModel)
    
    let documentsPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
    let persistentStoreURL = documentsPath.appendingPathComponent("Model.sqlite")
    
    try! coordinator.addPersistentStore(
      ofType: NSSQLiteStoreType,
      configurationName: nil,
      at: persistentStoreURL,
      options: [:]
    )

    container.loadPersistentStores { _, _ in }
    
    let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: "EntityA")
    try! context.fetch(fetchRequest) as! [EntityA] // array populated with multiple objects

I created the equivalent CoreStore code

    let dataStack = DataStack(xcodeModelName: "Model")

    let documentsPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
    let sqliteFileUrl = documentsPath.appendingPathComponent("Model.sqlite")
    
    let storage = SQLiteStore(fileURL: sqliteFileUrl)
    try! dataStack.addStorageAndWait(storage)

    try! dataStack.fetchAll(From<ModelA>(nil)) // array empty

The CoreData code returns the properly populated array while CoreStore returns an empty array. I tried initializing SQLiteStore with a number of different options, and tried the async versions of addStorage all to no avail. I set breakpoints in the relevant CoreStore functions, but could not find anything glaring that would indicate the issue. Not sure if this is a bug or if I am misusing CoreStore but any help here would be much appreciated.

@JohnEstropia
Copy link
Owner

@darrenasaro Since you're not getting an error at try! dataStack.fetchAll(), then it's likely your SQLite file does not contain records in the first place.

@darrenasaro
Copy link
Author

It does as evidenced by the CoreData implementation returning a populated array. I've swapped these implementations verbatim with all else equal and the CoreData one always returns a populated array while the CoreStore implementation always returns empty.

@JohnEstropia
Copy link
Owner

@darrenasaro Can you print the original file URL from here

let persistentStore = try! coordinator.addPersistentStore(
      ofType: NSSQLiteStoreType,
      configurationName: nil,
      at: persistentStoreURL,
      options: [:]
    )
print(persistentStore.url)

and check if it's still the same URL passed to SQLiteStore here?

let sqliteFileUrl = documentsPath.appendingPathComponent("Model.sqlite")

@darrenasaro
Copy link
Author

darrenasaro commented Mar 17, 2022

@JohnEstropia They are the same. I've recreated the issue in it's simplest form here
https://github.com/darrenasaro/fetch-demo

@JohnEstropia
Copy link
Owner

Thanks for isolating the issue! I'll investigate

@JohnEstropia
Copy link
Owner

JohnEstropia commented Mar 18, 2022

@darrenasaro Oh boy... It looks like NSPersistentContainer forces the file directory to where it likes. Try this out:

print("Expected URL:\n\(sqliteFileUrl)")
container.loadPersistentStores { persistentStore, _ in
    print("NSPersistentContainer:\n\(persistentStore.url!)")
}
let store = try! dataStack.addStorageAndWait(storage)
print("CoreStore:\n\(store.fileURL)")

Look at the output:

Expected URL:
file:///Users/<User>/Library/Developer/CoreSimulator/Devices/185DD2F2-A17F-4FBB-9D90-2BDA5B802F57/data/Containers/Data/Application/2732C567-34D7-42EF-942C-2DB5F34CD27F/Documents/Model.sqlite

NSPersistentContainer:
file:///Users/<User>/Library/Developer/CoreSimulator/Devices/185DD2F2-A17F-4FBB-9D90-2BDA5B802F57/data/Containers/Data/Application/2732C567-34D7-42EF-942C-2DB5F34CD27F/Library/Application%20Support/Model.sqlite

CoreStore:
file:///Users/<User>/Library/Developer/CoreSimulator/Devices/185DD2F2-A17F-4FBB-9D90-2BDA5B802F57/data/Containers/Data/Application/2732C567-34D7-42EF-942C-2DB5F34CD27F/Documents/Model.sqlite

Note that NSPersistentContainer moved the directory to Library/Application Support/, while CoreStore keeps it to where it's actually configured (/Documents/).

@JohnEstropia
Copy link
Owner

It looks like the behavior is correct if you use the NSPersistentStoreDescription method instead:
Screen Shot 2022-03-18 at 10 13 28

@JohnEstropia
Copy link
Owner

Since it looks like CoreStore is behaving correctly here, I'm marking this issue as a ios/compiler bug. I suggest that you find the original path actually created by the NSPersistentContainer for your store, and then pass it to CoreStore in your migrated code. I'd also recommend submitting a bug report to Apple through feedback assistant, since this issue seems destructive enough on its own.

@darrenasaro
Copy link
Author

@JohnEstropia Thank you for investigating this! Excited I can use this library now. This CoreData behavior definitely seems to be problematic. I actually downloaded the container to investigate and it looks like CoreData puts an sqlite file in /Documents/(or whatever directory you specify) and Library/Application Support/, the former file having just structure data and the latter containing structure data as well as actual records. Super weird. Will follow with a bug report.

@JohnEstropia
Copy link
Owner

Oh my, that's even worse. I'll try to explain that situation in the CoreStore README for future migrators. Thanks for investigating the behavior further

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants