iOS - Core Data set attribute primary key - ios

I am developing an application in Swift and started using Core Data recently.
I must define which attribute to my entity will be my primary key. For example:
I have an entity that has the attributes of the class:
id
name
age
I need the "id" attribute is my primary key.
May be the same in Objective-C, just need to know how to define it.

Each NSManagedObject has its own unique key built in which is available in its objectID property.
This id is internally used to link entities over its relations. There is no need to maintain an own id as a primary key as you are used to do in SQL.
You can always get the id by NSManagedObject.objectID.
Fetching an object by its id can be performed directly by the managed object context using NSMananagedObjectContext.objectWithId(...)

Why do you need id to be your primary key, it's not SQL and there is not primary key (even if behind core data it's SQL you don't use SQL and primary key). Rename your attribute id in userId, or entityId. When you want to get your entity with your id use a NSPredicate:
[NSPredicate predicateWithFormat:#"(entityId == %d)", entityId]

Related

CoreData attribute id is needed

I am currently practicing with Swift and Core Data, making an app with a login. When i fetch data from my users entity i receive this:
[<NSManagedObject: 0x7f8f1300c640> (entity: Users; id: 0xd000000000380000 <x-coredata://E67F6A37-4E56-4A55-A01E-940D8BD9EBE9/Users/p14> ; data: {
password = password;
userName = user;})]
Is there a way to obtain de id 0xd000000000380000? I am new using core data and i have only used SQL. I know Core data is not a DB but i think that id is like a primary key, isn't it?
I want to obtain that to use it to find an object of an entity.
Im trying something like this:
data.objectID.uriRepresentation().absoluteString
But it givings me only, it's not what I want to get.
x-coredata://E67F6A37-4E56-4A55-A01E-940D8BD9EBE9/Users/p14
Look at objectID property of your CoreData Entity.
But remember:
If the receiver has not yet been saved, the object ID is a temporary
value that will change when the object is saved.
https://developer.apple.com/documentation/coredata/nsmanagedobject/1506848-objectid?changes=_8

Should I define the primary key for each entity in Realm?

I have noticed that setting PK is not obligatory in Realm and simply can be omitted. But in documentation is stated that:
Indexes are created automatically for primary key properties.
And I'd like to clear up some questions:
1) What is the default value for PK is defined by Realm, if I don't assign it by myself. Is it hash or whatever ? (If I don't set PK and call [MyRealmObject primaryKey] it returns nil)
2) If this implicit PK is indexed by default ? Should I worry about it, because if it is not indexed, does it mean that it affects the general performance of this Entity (for example,fetching objects) ?
3) Is it a good practice to define PK every time for each RLMObject subclass or it isn't necessary for Realm and simply may rely on it's internal realization defined by Realm itself?
(Disclaimer: I work for Realm.)
Yep! Setting a primary key in Realm isn't obligatory, nor necessary, which is why it's completely up to the developer and the requirements of the app to determine whether it's necessary or not in their implementation.
In response to your questions:
1) There are no default values; you specify one of your own properties as a primary key. primaryKey returns nil by default since you need to override that yourself in order to indicate to Realm which property you want to act as a primary key. Some users have set integers as primary keys, but more often than not, using a UUID string is the most common.
2) There's no implicit primary key. You must use the [RLMObject primaryKey] method to explicitly state which property is the primary key, and THEN it will be indexed. :)
3) In my own (spare-time) development experience, I usually find having a primary key makes it a lot easier to identify and handle specific objects. For example, if you're passing an object across threads, you can simply pass the primary key value and use [RLMObject objectForPrimaryKey:] to refetch the object. Obviously this depends on your own implementation requirements. You probably shouldn't add a primary key unless you find out you really need one.
As an example, here's what you would add to your RLMObject subclass if you wanted to set a UUID string as a primary key:
#interface MyObject : RLMObject
#property NSString *uuid;
#end
#implementation MyObject
+ (NSString *)primaryKey
{
return #"uuid";
}
+ (NSDictionary *)defaultPropertyValues
{
#{#"uuid": [[NSUUID UUID] UUIDString]};
}
#end
I hope that helped!
Addendum: To elaborate upon some of the comments made below, primary keys are explicitly necessary for any Realm APIs that change their functionality depending on if an object with the same key already exists in the database. For example +[RLMObject createOrUpdateInRealm:] will add a new Realm object to the database if an object with that primary key doesn't already exist, and will simply update the existing object otherwise.
As such, in these instances where a primary key is a critical component of the subsequent logic, they are required. However, since these APIs are a subset of the different ways in which it is possible to add/update data in Realm, if you choose to not use them, you still not required to have a primary key.
The horse has been beaten to death already, but I couldn't help but reference the Realm code which throws an exception if a Realm Object is created or updated without having a primary key.
+ (instancetype)createOrUpdateInRealm:(RLMRealm *)realm withValue:(id)value {
// verify primary key
RLMObjectSchema *schema = [self sharedSchema];
if (!schema.primaryKeyProperty) {
NSString *reason = [NSString stringWithFormat:#"'%#' does not have a primary key and can not be updated", schema.className];
#throw [NSException exceptionWithName:#"RLMExecption" reason:reason userInfo:nil];
}
return (RLMObject *)RLMCreateObjectInRealmWithValue(realm, [self className], value, true);
}

Updating a primary key value on grails gorm

I'm wondering if I can change a value of a primary key member of a composite primary key in a Grails Domain class? For example having this domain:
class StudentHistory implements Serializable {
String studentNumber
String schoolYear
Integer yearLevel
String section
Float average
String status
static mapping = {
...
id composite: ["studentNumber", "schoolYear", "yearLevel", "section"]
...
}
}
Let say, On the schoolYear: "2014-2015", a certain yearLevel: 1 student with studentNumber: "2011-488-MN-0" transferred section from section: "1D" to section: "1N". Now to perform this record update, we do something similar inside a service:
StudentHistory record = StudentHistory.find {
eq("studentNumber", "2014-488-MN-0")
eq("schoolYear", "2014-2015")
eq("yearLevel", 1)
eq("section", "1D")
}
record.setSection("1N")
record.save(flush: true, insert: false)
The problem is that the update on the primary key doesn't take effect but when I tried to update other non-Primary fields such as average and status, updating them works fine (I tried performing an SQL directly on the database to confirm). How can I update primary keys?
PS: Now, based on this design, I know some will suggest that why not just create another record, then just fetch the record that has been last entered? But what I am required to do is to update that composite primary key instead.
PPS: Please don't suggest on removing the old instance, and create a new one, copying the old details except for the section. I cannot do that since many tables are connected to this table.
I believe it is a good practice to avoid changing primary keys. Primary key is a unique identifier of an object and changing it effectively means creating a new object. So if your composite primary key is mutable (or can mutate) then you should use a surrogate key - an artificial primary key. At the same time you can create a unique constraint on the 4 fields currently being your primary key.
In your case it would be:
static mapping = {
...
}
static constraints = {
studentNumber(unique: ["schoolYear", "yearLevel", "section"])
}
Hope it makes sense.

Update part of primary key Entity Framework 4.0

I've a table with a compose primary key (3 columns):
UTP_ID (ITEMId)
UTS_ID (CategoryID)
USS_ID (SubCategoryID)
When I try to change SubCategory ,for example,with EF 4 i get follow error:
utl.USS_ID = Convert.ToInt32(ddlSubSetor.SelectedItem.Value);
the property is part of the object's key information and cannot be modified
Any Ideias?Why i can't change it?
EF implements an Identity Map between primary key property values and object references. It doesn't allow to change the key for the same object instance.
I would do this with direct SQL:
objectContext.ExecuteStoreCommand(
"UPDATE MyTable SET USS_ID = {0} WHERE UTP_ID = {1} AND UTS_ID = {2} AND USS_ID = {3}",
Convert.ToInt32(ddlSubSetor.SelectedItem.Value),
utl.UTP_ID, utl.UTS_ID, utl.USS_ID);
Make sure that your entity utl is detached from the context because this code directly writes into the database table and the entity doesn't get any information about this change. But this avoids having to delete and recreate the entity (which might be impossible due to existing foreign key constraints on the old row in the database).
As a result of being part of the entity key the object needs to be deleted from the context and re-attached with the new primary key value.
The Entity Framework works by having a context which manages the state of the entities, a collection of entities (basically the table) and the entity itself (a row of data). As data is read from the database it is added to the entity's collection which in turn is managed by the context for changes of state. Changing an Entity's key is really deleting the entry from the database and inserting a new one. As a result to change an entity key, first delete the entity from it's collection, detach the entity object to allow key modification, change the primary key value and re-attach the entity to the collection. Finally call save changes in the context to apply the changes to the database.
The following code should produce the desired results:
Context.UTLs.DeleteObject(utl);
Context.UTLs.Detach(utl);
Context.SaveChanges();
utl.USS_ID = Convert.ToInt32(ddlSubSetor.SelectedItem.Value);
Context.UTLs.AddObject(utl).
Context.SaveChanges();

Self referencing foreign key - GUID - Entity framework 4 insert problems

I have successfully used EF4 to insert rows automatically with a server generated GUID:
http://leedumond.com/blog/using-a-guid-as-an-entitykey-in-entity-framework-4/
Now how does one perform this task if there exists a RowID (guid) and ParentRowID (guid) with a primary-foreign key constraint between the two? What would I set .ParentRowID to?
NewCut = New Row With
{
.ParentRowID = .RowID
}
SaveChanges throws a fit every time.
The fact that the primary key is a GUID is in fact irrelevant because I attempted the same test using a standard autogenerated integer without success.
The solution is as simple as the one you have posted.
Just create both parent and child entities in code, do not set Entity Key and not forget to set StoreGeneratedPattern for all server-generated Guid columns.
Then perform either MasterEntityInstance.Children.Add(ChildEntityInstance), or ChildEntityInstance.MasterEntity = MasTerEntityInstance and call SaveChanges.
After the SaveChanges call both guid properties will be populated with the correct Guid values, and ChildEntity.MasterEntity Entity Key will be populated with the necessary MasterEntity Entity Key value.

Resources