Normally when I backed up the core data file for my app, I would just copy the .sqlite file to another location while the app was running. But now that journaling (wal) is enabled, this does not work anymore. I cannot see a way for NSPersistentStoreCordinator or NSManagedObjectContext to write a new file. I'm guessing maybe I have 2 methods:
Close the persistent store and opening it again with #{#"journal_mode" : #"DELETE"} and then copy the .sqlite file.
Add another persistent store and maybe copy from the original ps to the new one ?
Any better ideas ?
Thank you.
Changing the journal mode will eliminate the journal files, so it's simple. I don't know that I'd trust it for your use, though-- because there's no guarantee that Core Data has actually flushed all new changes to the SQLite file. It might be OK, but there might be some in-memory changes that Core Data hasn't written out yet. This is almost certainly safe, but there's a small chance that it won't work right once in a while.
Option 2 would be safer, though more work. I'd create the second persistent store using NSPersistentStoreCoordinator's migratePersistentStore:toURL:options:withType:error: method (which the docs specifically mention as being useful for "save as" operations). Telling Core Data to create the copy for you should ensure that everything necessary is actually copied. Just don't do this on your main persistent store coordinator, because after migration, the PSC drops the reference to the original store object (the file's still there, but it's no longer used by that PSC). The steps would be
Create a new migrate-only NSPersistentStoreCoordinator and add your original persistent store file.
Use this new PSC to migrate to a new file URL.
Drop all reference to this new PSC, don't use it for anything else.
Related
I'm quite new to android and I am currently working on a app which should utilize a Room database. Following the documentation a room database can be created through the following lines:
myDatabase = Room.databaseBuilder(appContext, MyDatabase.class, "MyDB")
.build();
Now where did room create the database file?
It can't be found in my project folder.
The documentation doesn't mention anything about it and -generally speaking- barely gives any information about how this thing works.
Where is the database?
Does DatabaseBuilder.build() manage, to open the existing database created from previous app launches?
The list of questions is long.
Any information about the .build() thing aswell as further information about Room (misconceptions etc.) are very appreciated, for the documentation doesn't really make things clear for me.
Thank you!
Now where did room create the database file?
The database (a file) will be placed at the default location on the actual device which is data/data/<the_package_name>/database/MyDB.
In your case, as you have coded :-
myDatabase = Room.databaseBuilder(appContext, MyDatabase.class, "MyDB")
.build();
Then the database files will be: -
data/data/<your_package_name>/databases/MyDB
data/data/<your_package_name>/databases/MyDB-wal
data/data/<your_package_name>/databases/MyDB-shm
It can't be found in my project folder.
The database file is not part of the project, it is a file that is created and maintained on the actual device on which the App has been installed.
However, you can use Database Inspector (now App Inspection) on Android Studio to view the database e.g. :-
You can also view the files, if whatever device you test on allows access, by using Device File Explorer. e.g.
Does DatabaseBuilder.build() manage, to open the existing database created from previous app launches?
Yes, if the file exists then it is opened otherwise the file is created. If you uninstall the App this effectively delete's the file. The whole idea of a database is that it persists.
The build() undertakes various tasks, primarily seeing if the underlying file exists and then opening the file. In doing so it
extracts the version number that is stored in the file and compares the number against the number coded within the App (via the #Database).
If the version number from the App is greater then an attempt is tried to find a Migration (recently AutoMigration's have been added to Room).
compares the expected schema (according to the entities defined as part of the #Database), against what is found in the file.
A mismatch will result in the app crashing, so fixes would have to be made.
Note references to file is a simplification, by default Room uses a loggin mode called WAL (Write-Ahead Logging). In WAL mode there will be an additional 2 files that the SQLite routines maintain (you don't need to do anything):-
the database file name suffixed with -wal is the primary wal file into which changes are written (they are applied to the main database automatically).
the database file name suffixed with -shm (this is a WAL file for the WAL file).
Background
I've recently been shunted into the world of windows programming and I'm still trying to find my way around the best practices and ways of doing things. So I was just hoping for some pointers on use of the registry
Not particularly relevant but the background is that I am creating an installer in Golang, a couple of points to get out the way on that:
I am aware MSI's would usually be best practice for an installer (I have my reasons for going custom exe)
I know there are more obvious language choices than golang, just go with it
Current registry use
As part of the install process, I store several pieces of data in the registry:
run once commands:
Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce
I create a few entries here: to restart the process after a system reboot and to delete some temp files on reboot after uninstall
an uninstall entry:
Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Vendor
Product
Content here is the same as an MSI would create, I was careful not to create any additional custom fields here (all static data until uninstall)
an application entry:
Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Vendor\Product
I store some additional data about the installation here, some of which is needed for uninstall such as state info from before installation (again all static content)
a temporary entry:
Computer\HKEY_CURRENT_USER\SOFTWARE\Vendor\Product
I store some temporary data here which can include some sensitive user entered data (usernames/passwords). I run some symmetric encryption to obscure the data though my understanding is this is area of the registry is encrypted so only the user could access anyway (would like confirmation on that)
This data is used to resume after restart and then deleted
Questions
I'm looking for confirmation / corrections on my current use of the registry?
I now have need to pass some data between an application and a running service, this data would be updated every 1-2 minutes and would be a few bytes of JSON. Does the registry seem like a reasonable place to store variable data like this? If so is there a particular place that better for variable data - I was going to add it to:
Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Vendor\Product
HCKU isn't encrypted to my knowledge. It's stored in a file called NTUser.dat and could be loaded as a hive under HKEY_USERS and visible to other processes with sufficient rights to do so.
You would need to open up the rights to HKLM\SOFTWARE\Vendor\Product if you expect a user priv process to be able to write to it. If you want to pass data to a service you might want to use some sort of IPC pipe to do so. Not sure what's available in Golang for this.
I have a Document based Core Data app that saves with SQLite. While testing I save to a test file A.myappextension. Sometimes another file---"A.myappextension-shm"---is also created. Why is that?
Assuming that A.myappextension is your Core Data persistent store file, it happens because of SQLite journaling. You might also see A.myappextension-wal. Both of these extra files are SQLite journal files, and a lot of your data may actually be stored in them instead of in the main file. If you ever copy these files, or remove them, or do anything else that treats them as files instead of SQLite data, you'll need to copy/remove/whatever all of them.
What is the best way to save data in session variables in a classic web site?
I am maintaining a classic web site and want to be able to allow my users to demo all functionality of the site, this means allowing them to delete records.
The closet example I have seen so far are the demos of Telerik controls where they are saving the dataset in sessions on first load and allowing the user to manipulate the data.
How can I achieve the same in ASP with an MS Access backend?
If you want to persist the state over multiple pages (e.g. to demo you complete application) then it's a bit tricky.
I would suggest copying the MDB file for each session and using the copied version. This would ensure that every session uses its own data.
create a version of your access db which will be used as a fresh template for each user
on session copy the template and name it after the users session ID
use the individual MDB
Note: Then only drawback I can see here is that you need to remove the unused MDB files as it can get a lot after sometime. You could do it with a scheduled task or even on session start before you create a new one.
I am not sure what you can use to check if it's used or not but check the files creation date or maybe the LDF file can help you as well (if it does not exist = unused).
You can store a connection or inclusive an object in a session variable as far you remember what kind of variable are you storing at the retrieving time. I had never stored a dataset in a session variable but I had stored a lot of arrays in session variables so you can use the ADO Getrows method to locate a complete dataset into a session variable.
How big is the Access database? If your database is small enough (relative to the server capacity, expected number of users, and so forth) then I like the idea of using a fresh copy of the database for each user that runs the demo.
With this approach, you simplify your possible code paths. Otherwise this "are we in demo mode or not?" logic will permeate a heck of a lot of your code.
I'd do it like this...
When the user begins the demo, make a copy of the Access DB for that user to use. If your db is foo.mdb, copy it to /tempdb/foo_1234567890.mdb where 1234567890 is the user's session ID.
Alter the user's connection string to point to the fresh database copy. From this point on, your app can operate like "normal" with no further modifications.
Have a scheduled task that deletes all files in /tempdb with last-modified times more than __ hours in the past. If you don't have the ability to schedule tasks on the server (perhaps you're in a shared hosting environment, etc) then you could do this at the same time you do step #1.
I would like to modify a Spotlight metadata attribute of a file within my application (i.e. not in a Spotlight importer) but I can't find any API for doing so. Is it possible? Pointers to the relevant docs would be ideal.
In case it's helpful, here's my use case:
I want to store a reference to a file
system path in a Core Data store.
Ideally, I should be able to find the
file even if is moved, potentially
across mounted volumes. My understanding is that
an archived FSRef or AliasRecord will not do the trick because they
are not invariant wrt to moves across mounted
volumes. So my plan was to store a URL
and also to add a UUID (also stored in
the data store) to the file's
Spotlight metadata so that I could
perform a Spotlight query for that
UUID if the URL no longer pointed to
the file when the app goes back to
look for the file.
After further research, using Spotlight is not the best solution for the use case. The AliasRecord is a better persistent storage for a file. It automatically tracks moves/renames/etc. You can read more about AliasRecords here. Chris Hansen has written an Objective-C wrapper for AliasRecords, BDAlias. It's currently available from the rentzsch.com SVN.