I want to rename a property, sortOrder:
to sequence, within an NSManagedObject class.
(example illustration only)
And have followed the steps of Lightweight Migration.
The challenge is that the Lightweight Migration doesn't actually affect the NSManagedObject class (FormItems).
So the code still uses the sortOrder property. I can run a refactor-rename through XCode to change the code, but will that then break my backwards DB compatibility due to the renaming within the class?
What am I misunderstanding here?
Lightweight migration should work as expected. This statement
The challenge is that the Lightweight Migration doesn't actually affect the NSManagedObject class (FormItems).
is not necessarily true. It LW migration should affect all changed entities.
You can refactor your code to use the new name and
Create a new model version.
Make the changes to the property after changing to the new model version.
Make sure the persistent store has the right options.
NSMigratePersistentStoresAutomaticallyOption and
NSInferMappingModelAutomaticallyOption
As described by #Mundi, you need to create a new model version.
After that, you need to rename sortOrder as sequence in your code.
In mapping model, value expression for attribute "sequence" would be $source.sortOrder. This will retain all previous values after migration.
Related
How could I go about doing this programmatically? Subclass NSManagedObject and override -(void)awakeFromInsert;? Then I suppose set the attribute values in the methods implementation?
The way to get Core Data to do this, and IMO the right way to handle the situation, is to add another version of the model with the default values set on those properties, and configure automatic model migration.
I don't know whether migration will apply the new defaults to existing entities with nil values. (My guess would be not. Testing would bear the answer.)
Is there some reason you need to leave alone existing entities with nil values?
-awakeFromInsert would indeed be the right place to do this kind of thing in code.
I'm considering using flexjson to serialise my business objects to a file in an android application, simply using JSONSerializer().deepSerialise(myObject) and JSONDeserializer().deserialise(jsonString) with all the default transformers and object factories.
I'm hoping that once the application is released any changes to the business model should be accommodated by writing flexjsons transformers and object factories in the new release to maintain compatibility with previous versions.
What I'm not sure about is what changes the default transformers and object factories can cope with.
i.e if I add a field to a class and deserialise from an old version without the field into the new class will it fail or will the new field be null or 0 (if a number). Same question if I remove a field, what happens.
In standard java serialisation this is all documented here..
http://docs.oracle.com/javase/7/docs/platform/serialization/spec/version.html
But I cant find the equivalent information for flexjson, that deals explicitly with the issues surrounding versioning of objects, Is there any?
Cheers,
Phil.
Flexjson will look at the JSON first to find any fields it contains, and then looks for those fields on the Object you are deserializing into. So adding new fields to an object will not cause the deserialization process to fail. The new field will just not be populated from the JSON object (ie it will retain the value(s) set in the constructor or the initialization values).
If you remove a field from an object in the future Flexjson will simply not deserialize that value into the object because it won't find a setter for it.
So you can think about the getter/setter functions as a declaration on the JSON of what you want out of it. You aren't required to serialize/deserialize all values from the JSON object.
The only part that gets really tricky is if you rename fields, or change types on a field. Renaming field can be handled by keeping the older setter around and internally setting the new field in that older setter. You can mark it private or protected to hide it from the outside and Flexjson will still use it. If you change the type it is much more tricky. One option is to keep the older setter with the prior type around (like setFoo(String) and setFoo(List)) and adapt to the new type. The other option is to write your ObjectFactory to translate between to the two potential types. This of course is the hardest to do. The last option is don't do this without changing the name of the field, and use one of the other methods to translate.
One of my core data subclasses has an NSSet of items. It is often (but not always, so no NSOrderedSet) useful to instead retrieve an ordered NSArray, so I added orderedItems to the class, which sorts them.
I then ran into performance issues so decided to try caching the orderedItems. My plan is to use an iVar, _cachedOrderedItems in the class, which I will return if it is not null.
The snag comes with my use of categories. I read some good advice about putting all of my custom code in a category so that I can re-generate the core data class if necessary and not lose all my customizations. One of those customizations is the orderedItems method.
It seems I can not declare an iVar in the category itself. And if I try to put it in the core data class instead, I can not access it in the category.
Do I need to move my custom code back into the core data class? Or am I missing something?
I have also heard about Mogenerator, and would consider learning to use this if it would help.
You can use associative references to add ivars to a class any time you can't modify the original class, including in categories. For a detailed example, see Faking instance variables in Objective-C categories with Associative References.
You own the class, so you can use a class continuation (discussed here) instead of a category. This allows you to add instance variables.
You should definitely use mogenerator. See for example http://importantshock.wordpress.com/2006/12/19/mogenerator-or-how-i-nearly-abandoned-core-data/.
You can make an Aggregate target in XCode, add a Run Script with the following:
mogenerator -m path/to/your/datamodel.xcdatamodeld/version.xcdatamodel --template-var arc=true -M /CoreData/Generated -H /CoreData
For every NSManagedObject you get a class and a subclass. When updating your datamodel, run the script again and the base class will be updated, preserving all the changes you made to the managed object subclass. Remove --template-var arc=true for none arc.
I'm using DropCreateDatabaseIfModelChanges DB initializer class in Entity-framework-4.2. Problem is it creates a new database and old data is lost. I used seed method of this class to enter some new values. But in that way I cannot preserve my old data.
Does anyone know a way to drop and create a DB when model changes, without losing existing data?
Thank you.
No it is not possible with built-in database initializers and writing custom initializer preserving data would be very complex task. As alternative you can use Code First Migrations instead of initializers. Migrations allows incremental development of your database.
I want to programmatically (without Lightweight Migration) create a mapping model between two models that are exactly the same, except one of the entities (there are a bunch of entities) has different attributes. Let's call this entity "Person". And let's say the destination model has
1) added a new attribute called "address"
2) deleted an attribute called "eyeColor"
3) kept (i.e. not done anything with) an attribute called "name"
How would you create an NSMappingModel between these models programmatically? I happen to have some explicit questions that might help me do this by myself:
Q1) Do I have to create NSEntityMapping objects for all of the entities other than "Person", even if they remain unchanged?
Q2) How do I deal with the "address" attribute in "Person", which is a new one being created? Should I create an NSPropertyMapping for that somehow, that turns nothing into something ("address")?
Q3) How do I deal with the "name" attribute in "Person"? Do I have to create an NSPropertyMapping for that, even though it simply stays the same?
Q4) For the NSEntityMapping corresponding to "Person", is not creating any NSPropertyMapping for "eyeColor" a proper way to get it deleted? Or should I create an NSPropertyMapping for "eyeColor"? If yes, how would this object be created, i.e. what would determine that its purpose is to get rid of "eyeColor"?
Thank you in advance, and I apologize not being able to answer these questions myself, as the documenation really has no good example of how to create NSMappingModels programmatically. Note again that I'm not allowed to use Lightweight Migration. I must do this manually.
I've always used the automatic mapping feature of Xcode but it seems to me you can learn a lot from that as well. Make a model of (parts of) the source model, add a version, modify it to reflect the destination model and generate a Mapping Model (menu Design >> Mapping Model). If you then control-click the .xcmappingmodel Xcode has generated for you and tell the Finder to show you the contents of the package, you'll find an XML file inside that lists all the mappings. You can use the xml as a guide to help you recreate the process in code. Good luck.