Remove or Add an attribute to CoreData at runtime programmatically - ios

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.

Related

Cannot retrieve renamed attribute's value in Core Data

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.

iOS Realm object by reference or duplicate objects

I am using realm and I am not sure about this.
I have two option to do in Post. One is to save entire owner object and another is to save only user object ID. If I save entire object, is it object by reference? I don't want to increase database size.
The reason why I want to store entire object is that it is easy to access. It is like Post.User.email. I don't need to query. I read through realm though. https://realm.io/docs/objc/latest/
Thanks in advance.
No need to go by ID. In Realm, when you add a property of another RealmObject type, that will store the reference, not the entire object. So it will not take more space on disk than what you are expecting.
I am not sure if your diagram reflects your actual types, but note that when using collections, you want them to be of type RealmList<>, not Array<> (I am assuming you are writing C# as you referred to the Xamarin docs).

How to add same object type as different tables in same realm?

I'm using realm to cache certain network data coming down which is specific to the last search. I'd also like to be able to star or pin this data to save it for future usage. The data objects are exactly the same and I can't find anything in the documentation that allows me to save them in separate tables in Realm.
The easiest way to go about doing this would be to simply create a subclass of your model object with a different name (e.g., MyDataObject and its subclass MySavedDataObject). This will create a new table in the Realm database file with the same schema and will let you distinguish between the two types of objects.
You can then create a copy of a normal object as a saved object as simply as the following:
let myNewSavedObject = MySavedDataObject(value: myDataObject)
That all being said, instead of duplicating data, I would personally recommend being a bit more efficient with the existing data set. Surely simply adding an additional boolean property to the schema named something like saved would let you simply mark objects that you wish to keep without needing a whole second table. :)

How can a user add a new field to a table by creating a new attribute

I'm new to Core Data and I got stuck at this part of my xCode project.
I have created a core data entity "Person" and this entity has the following attributes:
name;
age;
birthday;
address;
and this attributes are getting displayed in a tableview. So far so good.
My problem is that I want the table to have an "Add Field" or "Add Row" cell so when the user wants to add more information in addition to these already created attributes he just clicks the cell and chooses the field name and type.
For example if he wants the person's "phone number" in the detail view of the table he names the new field "phone number" and chooses its type "number". Then he has an extra field where he can add the person's phone number.
How can I do this in core data? Is there a way for a user to manually add a new attribute to an entity and choosing its format? What is the best approach? Thanks.
You can't do exactly what you want with Core Data. Core Data can't change structure except if you make a new version of your design, but you do that in xcode.
But you can easily add another table called f.ex. information, which links to the person single connection and has the person linking back many to the information table.
This way, you can add as many fields and values as you want, of course all the extra fields you add would follow the same person, so if you want to use cellPhone field, you must add that to all.
I would recommend that you use direct SQL, and don't use Core Data. Core Data is not a database, it is an object store, and when you get better at iOS development, you will understand the difference, it is much bigger than you might think at first.
There is an excellent high level library for SQLite, called FMDB, you can find it on github here : https://github.com/ccgus/fmdb
Here you can do direct SQL queries like "Alter Table" and more on the fly, though what you are after isn't very simple, it could be real fun project to do.
Good luck with this.
I don't think this is directly possible in Core Data because its purpose is object persistence and you can't add new properties to objects dynamically. It could be faked to some degree using a to-many relationship to an "extra property" entity that had name, value (as string), and data type fields.
I believe your best option would be using SQLite in order to modify the table structure on the fly. (http://www.sqlite.org/lang_altertable.html)
My last company did something like this, but its not trivial. I don't have access to the code so this is more or less going to be from memory.
you provide transformable property in your entity (which will be a dictionary)
the model object has to provide the getter and setter for this that in turn drive the primitive methods to set/get an attribute
you provide a getter/setter along the lines of -objectForKey and -setObject forKey, which read and write values
when you are told to 'fault', you update the dictionary in the entity
In summary, maintain a dictionary of key value pairs. Perhaps you maintain a shadow dictionary that gets initialized and updated as needed. Its been around 4 years since I last saw this code so a little fuzzy on it. But you should get the idea. It was like magic - you can arbitrarily set any key/value pair (assuming string keys and NSCoding compliant values), and can always ask for the keys by asking the dictionary for its current set of keys.

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