Cannot retrieve renamed attribute's value in Core Data - ios

In my iOS app's core data model, I had an Entity called Fish with a string attribute called mainText. I renamed this attribute to questionText. The CRUD operations works fine for the new data. However, I cannot read the old data, the one written when the attribute was called mainText. Here is what I have tried:
Renaming it back to mainText, it does not work.
Adding a new attribute called like the old one, mainText, it does not work.
How would you proceed to retrieve the old data's values (the one wrote when the attribute was still called mainText) ?

If you want to rename an attribute and keep the old data, there are two things you need to do:
Create a new version of the data model. You probably already did this, or your app would not have been able to load the old data at all. If not though, make sure you keep your changes in a different version of the model file. The old model version needs to be available or migration won't work.
On this property, set the "renaming identifier" field to contain the old name of the attribute. This will tell Core Data that it should migrate values to the new attribute name. Without that it can't tell if you want to rename the attribute or if you want to delete the old one and add a new, different attribute. In the model editor, you'll find this on the right when you select the new attribute:
You may find Apple's guide to lightweight migration to be useful too.

Related

Remove or Add an attribute to CoreData at runtime programmatically

I have to create and remove attributes based on an api response in Objective C.
For example, Now my api response contains fields "facebook", "whatsapp" and "viber". But in future the reponse can add "youtube". Based on this response, I have to remove all the attributes and values of an entity "Social", and create Four attributes now and set values.
How to do that programmatically? Because the default *.xcdatamodeld file cant help me here, right?
Note: My project is in objective C.
The data model is mutable when the app starts-- you can completely build the model in code, and not use the model editor, for example. But as soon as you load a persistent store file, you must treat the model as fixed. Any changes after loading a persistent store will cause crashes. That means any changes would have to happen before calling either loadPersistentStores(completionHandler:) or addPersistentStore(with:completionHandler:).
Alexander's suggestion of optional attributes is a good one. If you need the model to be more dynamic, you would need to create a new related entity which would store the service name plus whatever information you need to save about the service. If you did this, your Social entity would have a to-many relationship to a new entity called something like Service. Service would have a string property called name that would have values like twitter, facebook, youtube, etc. It would also have whatever other attributes you need to save about the service.
You can create all 4 fields in advance and just make them optional and fill them depending on the server response. But you cannot add new attributes in runtime. Your *.xcdatamodeld file compiles into *.momd and it contains all the data to create tables in the DB since Core Data by default works with SQLite under the hood and it's a relational database management system.
To make attributes optional you should check that.
And then newly created objects contain nil as default values of object properties. So, in your case your "youtube" property of Social object will be just nil.

Coredata migration: change value type

I've an already shipped application that use Coredata so save all the data. My model defines a value of type BinaryData and I would like to change the type to Integer.
Currently that field is unused, but his type is incorrect. Can I migrate my store without pain? I've tried some approaches but none of them actually worked.
Any ideas?
The proper way would be to use a mapping model, but I think there is a much more practical solution for you. Because the field was never used, just delete it. The overhead is practically inexistent.
Now all you have to do is lightweight migration:
Create a new model version.
Add the Int attribute, delete the old one.
Change the active model version to the new one.
Change the options in your call to addPersistentStore to include
NSMigratePersistentStoresAutomaticallyOption
NSInferMappingModelAutomaticallyOption
Change your code to use the new attribute
Eliminate all potential uses of the old attribute from your code
Test it thoroughly before you upload ;-).

Is CoreData migration proper in this scenario?

I have an app that utilizes Core Data. One of the Core Data entities is an NSInteger that represents an enumeration. In my next revision, the enumeration values have changed and I need to remap the old enums to the new enums.
Is Core Data migration an appropriate approach in this case, as the model has not changed, just my interpretation of the data. I've attempted to implement a migration policy, but I can't get it working (my migration policy never executes).
Thanks!
--John
If you've added a couple of new values to the end of the enum, then I wouldn't migrate anything, just make sure the old numbers still equal the old values.
If you have changed the value that each enum represents, then you should not have used an enum in the first place as enums are never supposed to change. In this case I would add a new column or relationship and probably better not to use an enum this time.
Leave the old enum in the database structure, but have your subclass of NSManagedObject handle updating both values whenever either one changes (or something like that).

UpdateModel() cannot assign new value to navigation property (entity reference)

This happens in ASP.NET MVC 2, .NET 4 (EF 4). My Address entity has a reference to the Post reference. Zip is the primary key of the Post entity. Another property in Post entity is CityName. In my views I allow users to change the CityName for the address which automatically (via jquery) loads up the corresponding Zip and stores it inside a hidden field.
When posted, both values are posted fine and binded to the Address's Post reference. But UpdateModel() fails to update them. It says that the Zip is part of the entity's Entity Key and cannot be changed.
I would gladly load up the Post entity by the new Zip and manually assign it to the existing Address but for all other properties I stall want to rely on UpdateModel().
How can I achieve that? One would think that in EF4 stuff like this has been resolved..
By default the entity framework generated classes put restrictions on changing primary key values. This is good. You shouldn't change a PK for any reason at all. Changing PKs outside of add scenarios has pretty huge ramifications for state tracking and the general health of your system.
To solve this problem you want to tell UpdateModel not to update your primary keys using the exclude parameter.

Entity Framework creating new record instead of modifying existing one

I'm using Entity Framework with an AS.NET MVC application. I need to allow the user to create new records and modify existing ones. I am able to fetch existing records no problem, but when I pass back in the edited entity and try to save it it creates a new one and saves it and leaves the original unmodified.
I am getting the object from EF using the primary key (e.g. ID number for an employee record). I successfully retrieve it, and set the MergeOption like so:
Context.Sector.MergeOption = MergeOption.NoTracking;
I am able to trace that the object has the correct data (using the key of the original record) all the way down to the point where I call:
Context.SaveChanges();
However, after that, the new record is created instead of modifying the existing one.
Is there something obvious I am missing here? I would have thought that retrieving the object and changing some of its values (not the ID) and saving it would just work, but obviously not.
Thanks,
Chris
"NoTracking means that the ObjectStateManager is bypassed and therefore every access to the Entity Objects results in a fetch from the database and the creation of new objects."
-- http://blog.dynatrace.com/2009/03/11/adonet-entity-framework-unexpected-behaviour-with-mergeoptions/
I don't think NoTracking is what you want.
From your comment: "distributed across various tiers and some proprietary libraries"
Are you new()ing up a ObjectContext, closing it or losing the reference to it, and then trying to save your object to a new() or different ObjectContext?
If so your losing all of your change tracking information. If this is the case then you want to call the Attach() method to reattach the entity to the context, ApplyPropertyChanges() and then finally SaveChanges().
Julie Lerman has a pretty good blog post that outlines all the different change tracking options and techniques that are available. You should also check out this MSDN article on the same subject.

Resources