change attribute value in Core Data in already published application - ios

(Actually, I don't know how to formulate my question, so in google I found nothing.)
So, the situation: In app in appstore I've the Core Data entity (let's say Weather), one of its attributes is Speed type String. Now it contains single line (e.g. 5 mps), but now I want it to contain an array-like string (e.g. 5 mps; 6.4 mps; ...) also change name from "Speed" to "SpeedHistory".
And I made a new model verison, chose it (it has little checkbox now), renamed the attribute, set "Renaming ID":"Speed" and now: how should I act, to prevent user's of old version data crash?
Could you give me some advice, please?
P.S. Data in Weather Entity is fulfilled by user. And I'm using MagicalRecord.

This is a rather common issue. When you update your model when using core data you have to migrate it. You can follow this tutorial which explains what you should do to fix your issue:
http://www.raywenderlich.com/27657
A lightweight migration is also relatively simple and can be performed safely. You only need to worry when the changes in your model kind of require a change in logic.

Changing the type of a column is something that can't be done with lightweight migrations. If you want to migrate the users' data when they upgrade to your new model version, you'll need to create a mapping model. This process is described in the Mapping Overview section of Apple's Core Data Model Versioning and Data Migration Programming Guide.
I haven't had much success with mapping models, as they seem to be very memory-hungry.
Have you considered adding the SpeedHistory attribute without removing the Speed attribute or setting a renaming identifier? Then in your model class you could override awakeFromFetch:, check whether there's a Speed, and if there is then set the SpeedHistory as appropriate and clear the Speed. You'll migrate the objects one at a time, on an as-needed basis.

Related

Core Data entity new attribute - is new model version required

I have a very simple question related to the usage of lightweight migration and Core Data versioning.
It is well known that when modifying Core Data model one needs to ensure that a transition can occur from the old model to the new one.
For simple changes (like adding a new attribute) lightweight migration is all that is needed. There is lots of information online suggesting that to ensure that all works well one needs to:
Create new model version
Make the necessary modification
Assign the modified version as the new current version
Support lightweight migration with the options:
let options = [NSMigratePersistentStoresAutomaticallyOption:true,NSInferMappingModelAutomaticallyOption:true]
This approach definitely works well. However, I have also discovered that for simple changes a new model version is not needed. In one of my apps I have already released several updates which included changes to Core Data model (all of them contained additions of new attributes) and lightweight migration was successfully applied without any new model versions.
From my experience it seems that when one modifies Core Data version it is assigned a new identifier of some kind. Then, when this version is launched on the phone which has an older version of this model, lightweight migration is performed without any issues for simple changes.
However, in the light of the fact that every tutorial suggests to create a new model version can someone tell me if I am missing some scenario under which my approach will result in the crash?
Hmn... I think you have missed one thing. If your 'new attribute' is mandatory field, then you must have assign a default value of that mandatory field.
note: if you miss to set default value of that non-optional attribute then that attribute will be assigned by a nil value which eventually causes a crash.

How the Core Data Migration will work for two projects?

I'm working on an app which using core data (one app is already live on the AppStore). OK, now I want to make it fully functional for iOS8 and client also asked me to make a good change in UI and its structure so I started a complete new project and decided to code it my self. Everything works fine, then client emailed me and confirm that, new version of app should store & fetch existing values from the database if existing app will get update. I feel bad here.
I know core data migration is possible ( I read this too, but there's some glitches in my mind about this concept.
As I told, I started a new project though is it possible to add a new version of the model?
Our entities and attributes names are not same. I named it the way I want.
Our model name is same. e.g. Somename.xcdatamodel
My app will update to the existing app on the AppStore.
How I can migrate the existing core data database to the new one?
Is this possible? How?
Any suggestions and help on this would be appreciated.
Note:
I read this question, Core Data Migration: How to delete the Core Data stack? and found that there's no issue if I delete the previous model? What you suggest?
If you need to migrate and keep the existing data, you should read more about writing custom policy Core Data Versioning Guide. Read this guide completely to get to know which category your app migration falls in.
1. Lightweight migration.
2. Or you have to write your own custom policy.
As far as i can tell from the details you provided it looks like it might be a lightweight migration for which you do not have to do anything you can just add a new version to xcdatamodel and mapping models. If not then you have to write your own custom policy and mapping models.
Also make sure you test upgrade properly.

Consideration of multiple datamodel versions with Core Data light weight migration

I'm new to Core Data migrations. I read a tutorial about light weight migration. The scene is like this:
I created a data model, it is version-1.
So I have to add an attribute in my entity, I did this using a light weight migration. Now the data model is version-2.
Sadly, I need to add another attribute again. I still use a light weight migration to do that, now the data model is version-3.
If my user updates quite often, it is alright. But what if my user has data model version-1, and updates the app directly to data model version-3? Do I need to write code to handle the migration from v1 to v3, or is it handled automatically for me since I used light weight migration?
Your app needs to be able to handle all possible migrations that might happen. If the current version is the third, it must be possible to upgrade all previous versions to version 3.
This doesn't mean you actually have to write code for the migration. If automatic lightweight migration is possible, then it will work, without any custom migration code. Whether that works depends on how the model has changed. If a v1 --> v3 migration is possible with automatic lightweight migration, you can use that. If it's not possible with automatic lightweight migration, you need to handle it yourself. The answer depends only on how similar version 1 is to version 3, and has nothing to do with the fact that there was also a version 2.
In my experience this works automatically. It's fairly easy to test, also, so I would recommend that. Create v1, install app on device, add some data to the app. Create v2, v3, then run app on same device. Does it work?
Also, you need to be careful when writing new app code that you don't assume that the new fields have valid data in them for any existing records in the database at time of upgrade.

iOS CoreData Migration using Custom Mapping Models with multiple historical database versions

I have an app and many history versions of the database.
Our users are typically "once in a year" users, so this means you can never be sure which version of the database their app is running on.
Now in my new version of the database I need to do some custom migration.
The method I use to do this is described in this tutorial: http://9elements.com/io/index.php/customizing-core-data-migrations/
To summarize: I have to make Custom Mapping Models so that I can write my own migration policies for some fields.
Now when I create a Custom Mapping Model, I have to select a Source "xcdatamodel" and a Destination "xcdatamodel" (where "destination" is te new version of my database).
My question is, if I want to do this custom migration from all possible versions, do I need to create multiple Custom Mapping Models, all with a different source, or is there a smarter way to do this?
Or is CoreData smart enough to recognize this?
The short answer is yes; you need to test every migration from every source model to your current destination model. If that migration requires a custom mapping then you will need to have a mapping for that pair.
Core Data does not understand versions; it only understands source and destination. If there is not a way to get from A to B then it will fail. If it can migrate from A to B automatically and you have the option turned on, then it will. Otherwise a heavy (manual) migration is required.
Keep in mind that heavy migrations are VERY labor intensive and I strictly recommend avoiding them. I have found it is far more efficient to export (for example to JSON) and import the data back in then it is to do a heavy migration.
It is enough to have a consistent sequential series of migration models up to the current version. Core Data is "smart" enough to execute the migrations you tell it to migrate in the given order.

Considering a new Rails app with existing data (not a db, actual data) -- what is the best way to proceed?

I have been tasked with developing a new retail e-commerce storefront for my current job, and I am considering tackling it with RoR to A) Build a "real" project with my limited Rails knowledge, and B) Give management quick turnaround and feedback (they are wanting to get this done ASAP and their deadlines are rather unrealistic - I'm talking a couple of weeks to go from nothing to working model so they can start to market it with SEO/SEM and, I kid you not, "video blogging" because my boss heard that's the future).
We do have a database structure in place but it's absolutely terrible and was thrown together without rhyme nor reason, so I'm going to largely ignore it and create a new database from scratch; however, I have existing data that I need to load into the application (like I said, it's an e-commerce app and we have the product data). I need to massage this data into a usable format because our supplier provides it to us with cryptic, abbreviated column names and it's highly denormalized, especially in the categories (I've posted a question regarding it before - basically the categories table has six fields, one for each category/subcategory, with some of them being blank if that category doesn't apply).
There are two main issues that are giving me second thoughts:
As I said the data needs to be put into a "proper" database schema; I can't just load it as-is. I have some thoughts as to a good data model for it, but my analysis is not completed yet. There would end up being a large amount of joins tables to link various things together (e.g. products_categories, products_attributes, products_prices) etc and these tables would link products not via an ID but by their SKU (see below).
Everything already has an ID that's generated for it, but anything new I add needs to have one autogenerated; I doubt this will be a problem with any mature RDBMS, but I know Rails likes to generate IDs itself. Also, almost all of the product-related tables are linked by SKUs (and in the data provided by the supplier are actually a composite key consisting of the prefix and stock number, which combined make up the full SKU), not by IDs and I'm not sure if this will be a performance issue (of course, I could always manually create indexes on these columns to speed it up). It does mean that I'll need to break away from the Rails conventions, however.
In short, I think that Rails might be a good choice as far as time-to-market and ease-of-development, but having to work with the existing data content might turn into a pain because the application will need to be developed around that, instead of the "traditional" Rails app, and that factor is giving me major doubts about using Rails. There are also some other issues (having to set up a Linux server, and the fact that the area I live in has very few Rails developers so if I left the company I'd basically be holding them hostage as far as updates/modifications). I'm really unsure as to the best path to proceed.
I would develop the app as if you didn't have the data. Use the ORM and make your database the best it can be, but of course keep in mind what data you have to populate it with (eg: don't make crazy new constraints for things that will leave you going through old data record by record).
When you're done and tested, write an import script that pulls your real data onto your new database.
It's not that different from the conventional design/development model... Apart from you can do your data-input in a semi-automated fashion.
I was in the same situation not too long ago — a crappy PHP app that held ten years worth of all company data.
What I did was simply create a Migration model and added methods to import each resource.
class Migration
def migration_all
self.jobs
end
def self.jobs
...
end
end
The cool thing about this is that you can arrange which order resources are imported as one will likely reference another. I also added methods that directly modified the db schema. One nice trick if you have to keep an existing primary key is to create a field named 'legacy_id', copy over your existing primary key, and when you're done, simply remove the 'id' field, rename the 'legacy_id' field to 'id', then add the primary_key constraint on the new 'id' field.
Don't use the SKU as the unique key for each product - use the standard Rails incremented id.
SKU could change as it may be misentered, etc and that would make it a nightmare to change all of the references from other tables. Put your current id in a sku column, index it and update the references in your other tables to the Rails ids.
You'd be able to do Product.find_by_sku(params[:sku]) in your controllers, set up a /products/:sku route, etc. I don't see what you'd gain (other than a headache) by using your non generated ids as the database primary keys.
I'd also suggest running your old data through your app's validations to make sure you are not loading up a bunch of inconsistencies and erros. It will help your app run smoothly and highlight existing data errors at a point where you can fix them.
Don't assume the existing data is valid just because it is already there.

Resources