Merging CoreData SQL files - objective-c

I've been wrestling with this problem with quite some time now and still have yet to figure out the most efficient way of dealing with it. Here are the details:
I have an app that uses Core Data to store the content for the app to show. The app downloads the content in the form of a SQLite database and attempts to merge it with it's local version. This is necessary because the downloaded content is often needs to be combined with content that the user downloaded prior.
To make things more complicated, on my end I also need a way of combining these files so their clean to download (in other words no extraneous relations or isolated objects in the core data file). I have already built the editor for this, but again I run into the problem of merging these sqlite files.
I'd like to find a better way of combining these sqlite databases if that even exists. I've seen that you can add many different store files using a persistent store coordinator, but coordinating all of the correct stores into a single download package becomes more difficult and dangerous.
The question is: what is the best way to use multiple sql stores and either make them into one convenient .sqlite file or have them operate seamlessly?

First, don't think of this as an SQLite problem. It is a Core Data problem. If you use Core Data and SQLite in the same paragraph, you have already lost. CD does (sometimes) use SQLite as its backing store, but that knowledge doesn't help you solve this problem.
When I have had to solve the problem of combining static and user-generated data, I have usually used two different data models, with a unique ID on the static side under my control. Any combined references between static and live data I handle programmatically, which has worked fine because the user data is tiny compared to my static data.
You might also investigate fetched properties, which allow you to obtain values from a different persistent store.
I think merging your original static data with updated static data is the wrong way to go. That sort of operation will take a long time on the device.
Can you use three different persistent stores? The first would be bundled with your application, available immediately. The second would be updated data, downloaded from a server, and would be a complete replacement for the first. Finally you'd have a userdata store, connected to master data either with fetched properties or your roll-your-own unique ID.
It's also possible that Core Data is the wrong hammer for this particular nail. If you have a lot of SQLite expertise, and if you really are more comfortable working with SQLite than with Core Data, just skip Core Data. Do the entire thing in direct SQLite.

Related

Saving Data - Core Data vs plist file

I'm writing an iOS applications that saves Music albums(just an exercise I'm doing for the fun of it) .
For every Album there's a singer, song names, time, and a picture
The final result will be a lot of objects with a lot of details including a picture attached to every object. Should I even consider doing something like that with plist? (can pictures be stored in a plist?)
What's the best way to save and access that data?
I'm new to iOS and from the training videos I've seen Core Data is not recommend for the beginner user. Is that really the case?
If I'm going with plist, should I create one plist for every genre for example rap.plist , rock.plist etc' or just a big data.plist?
Thanks
I would go for core data. If you choose the right template when you create your new project in xcode then reduce the once-off overhead work significantly.
With that simple structure I would say that the templates provides nearly everything you need. Just define your model and layout and off you go.
There is just the images where I would spend a bit more time in thinking it over. I personally never put the image data into core data itself. I rather stored them as file and within my core data model I just stored the path and filename to access it. As file name I simply used a timestamp. You could use some auto-increment or other unique id technique but a time stamp would do as well. It will not be visible to the user anyway.
I think the best way you can do this, since you are new to IOS is by using sqlite. Save all the information you want in your local database and display it on the screen.
You can use plist if you have data structure that is small.
Note that property lists should be used for data that consists primarily
of strings and numbers. They are very inefficient when used with large blocks
of binary data. A property list is probably the easiest to maintain, but it will be loaded into memory all at once. This could eat up a lot of the device's memory.
With Sqlite you will easily be able delete , edit, insert your data into the database.
Core data also uses sqlite for data storage only it helps you to manage your data objects, their relationships and dependencies with minimal code.
And since your are new getting started with core data would not be such a good idea i think.. so i would suggest start off with normal sqlite. Save the data in one of your folders of your app and store their path in the database.
You dont have to write different plists.. You can use the same one if you are using.
EDIT : here is a link that will help you with learning sqlite
http://www.iosdevelopment.be/sqlite-tutorial/
you need some more code to set up the core data stack (the store coordinator, the store, the object model, and a context)
it is a tad more complicated but that shouldnt scare you off.
Reading a plist is indeed dead easy but while good for smaller data (like the info.plist) it doesnt scale and soon you need a fullblown DB
As you edited your original question an decided to go with plist now.
In that case I would go for one plist per ablum and one overall plist for the list of albums.
You could, of course, use more plists for categories etc.
However, if you are thinking of data structures like categories you are far better off with core data. Especially when it comes to searching.
No one seems to be mentioning SQLLite, I would go that way and for reasons that I explain here ( https://stackoverflow.com/a/12619813/1104563 ). Hope this helps!
coredata is a apple provided persistant tool, while plist is XML file. The reason why core data is not recommended for beginner, I think, is core data is more difficult than plist from programming perspective. For your application, obviously core data is more suitable. But alternatively, you may also use archive file, that's between core data and plist.

Provide example for why it is not advisable to store images in CoreData?

this question has been asked many times, I have read many users telling that it is not advisable to store images in a DB, in particular within CoreData. By they all seems to omit the reason why they would do so. Even Apple documentation state this, and everybody points to that direction, and every discussion end like this "well you can, but storing the path is better".
Apart from opinions, I would like to have a concrete example of why it is not a good solution.
I explain better, I have a strong background in building Web Application. A concrete example I would give from my point of view could be: do not store images in a DB, but rather the path to them, because you can have them served them by the web server, which can apply all of its caching issues.
But in a desktop environment, especially in iOS application, what are the downside of having stored in Core Data using sqllite, providing that:
There's a separate entity holding the images, it is not an attribute
of main entity
Also seems to be a limit of 100kb for images. Why ? What does happen with a 110,120...200kb ecc ?
thanks
There's nothing special about what Core Data normally does here. It's just using an SQLite database. You can put large blobs of data into it, but it just doesn't scale all that well. You can read more about it here: Internal Versus External BLOBs in SQLite.
That said, Core Data has support for external blobs which in Core Data terminology is called stored in external record (iOS 5.0 and later). Again, there's nothing magic about it, it's just storing the large pieces of data in the file system separately from the SQLite db itself. The benefit is that Core Data updates all this for you.
When you're in Xcode, there'll be a checkbox called Allows External Storage that you can check for Binary Data properties.
The filesystem, and the API:s surrounding it is (just like a webserver) optimized to serve files, of any size, and to apply caching where appropriate.
CoreData is optimized for handling an object graph with tiny pieces of data, like integers and short strings.
Also, there are a number of other issues that tend to creep up on you, like periodically vacuuming the SQLite database CoreData uses, or it won't be able to shrink, just grow.
Leonardo,
With Lion/iOS 5, Core Data started handling file system storage of large BLOBs for you.
The choice is really determined by how many images you are going to have open. If you have many, then you should keep them in the DB. Why? Because you only have a modest number of file descriptors, one of which is used for each open image stored in the file system.
That said, there is still a reason to manage the files yourself. If your BLOBs are really big, say 2+ MB, you will want to map them into memory and not just read them in. (When the memory warnings come, this lets the OS automatically purge them from your resident memory. This is a very good thing.) Even so, you still have the limited number of file descriptors problem.
Andrew

iOS core data:how to use preloaded sqlite database which contains multiple tables

my app has a sqlite database which is already preloaded with data. the database has many tables. i want to show a list of tables, so i have to query database or just list my entities?! when user taps a table name the next uitableview shows the data of that specified table. there are no relations between tables. only selecting from database matters right now.
what would be the best way to go forward? sqlite api or core data. i'm new to iOS programming. i'm reading about core data. it sounds good but i'm perplexed how to solve this problem.
edit:by the way the table are identical. all of them have the same attributes. i have spilted in tables so that each table represent a category, and i suppose it would best for memory usage on the iDevices.
I would strongly suggest you try to learn the Core Data methods to deal with your data as object graphs. Its is really worth the effort because you get so much additional functionality for table views, etc. all with great automatic memory management. Memory will easily become quite an issue if you deal with raw SQLite and have a lot of data or complex tables.
Do this:
Create the entities in your core data model. Access the existing SQLite store and recreate all the data for your new core data tables. This is normally quite memory and processor intensive, so you typically do this on the simulator, not on the device.
After you have successfully imported the data, you can remove the sqlite libraries and import functions and work with your true core data persistent store.
This is a bit of effort, but I guarantee it is well worth it.
I'd use SQLite since you already have populated .sqlite file. If you want to painlessly use SQLite I suggest getting along with FMDB.
As for the way that your tables are identical I can only advice you to create a shared method like - (void)itemsWithCategory:(NSString *)category and your whole DB communications will be through this function.

What is the common way to insert master data to sqlite in Core Data?

I'm studying using Core Data.
After I create the entity in Xcode, I want to insert some data, which is master data, what is the common way or should I say best-practice to achieve this?
I googled a little and found out where the real sqlite file that generated by xcode located. It looks like /Users/<Username>/Library/Application Support/iPhone Simulator/User/Application/<Application GUID>/Documents/<database name.sqlite>
Now I'm wondering if I edit the sqlite (just to insert data) file directly is a proper way?
If what you mean is a preset database setup for all new database instances, there's a couple of ways to do this.
Programmatically , you can insert Entities into the managedObjectContext with a bunch of code. This will get be slightly painful for anything other than a fairly trivial dataset but the advantage is that you can use all of NSPersistantDocument for virtually free.
Use your app to create the dataset and then save it in the apps bundle as a read-only copy which you can clone as needed when a user creates a new database. A bit messier if you are using the NSPersistantDocument architecture.
Do what you said in the first place . Use an sqlite3 client to inject data into the database to create a read-only copy like 2, but the risk is that there is more to the database structure that CoreData inserts which you dont know about so you might put a bit of work in to find that CoreData cannot read the db after you mess with it in sqlite3. I haven't tried but it might work.
IMHO 1 is the best practice as you get a bunch of free behavior from NSPersistantDocument
The only sane way to populate a data set into a Core Data sqlite store is programatically.
For iPhone apps, it's common for people to write small OS X apps to generate sqlite files, which can then be added to the app bundle.
The Core Data sqlite store is complex, and Apple officially considers it an opaque data store. Attempting to modify or create data in the store manually is likely to cause data corruption. Don't do it.

Is there an editor for inserting/editing rows into a Core Data DB?

I've created a Core Data schema in xcode (3.2.5 if it matters) so I have the .xcdatamodel file with the proper entities and relations.
Now - How can I insert data, edit data and/or delete data from it, NOT from within the code ?
Like what phpMyAdmin is for MySql.
Thanks.
Core Data is meant to be used programmatically. Once you run the app once, it should create a file somewhere on disk (exactly where is probably specified in the AppDelegate class). It is likely that this file will be a SQLite database, but it doesn't have to be (the point of Core Data is to abstract your data away from the file format used to store it). It could also be an XML file or a binary file.
If it's a SQLite file, then you can open it in your favorite SQLite editor.
HOWEVER
The schema used in the SQLite format is not documented. If you go mucking around in it, you might get stuff to work, but it's also very likely that you could irreparably screw it up. (If it's an XML file or a binary file, you're probably totally out of luck)
In the end, Core Data is supposed to be used programmatically. To use it in a different way (such as what you're asking for) would be to use it in a way for which it was not intended and therefore not designed.
I don't know if you already solved your problem, but there's this SQLite Manager plug-in for firefox: http://code.google.com/p/sqlite-manager/
I haven't tried importing data or using the INSERT command to insert individual rows, but you could give it a try. It's free and works very well for me as is.
There's quite a few database management tools available for sqlite that allow you to do this. I've tried a few but to be honest none of them have impressed me that much as yet.
Would be great to have something like Toad available.
Anyway, find wherever your database file is, then drop it onto whichever application.
You can then add, delete, and edit rows and columns.
Of course, you will need to maintain any foreign keys and such like.
I find the generated Core Data models to be pretty easy to understand.
Example tools are SQLite Database Browser (free), SQLiteManager (not free), and Base. A quick Google search should reveal those and a few more.
I normally use SQLite Database Browser although it does crash occasionally.
See Christian Kienle's Core data editor. It's not free, but is designed to work directly with core data models and stores via Apple's API, supports binary data, builds relationships and even triggers validation, etc. I've found it's worth the $20.