Fetching Core Data Related Objects - core-data

I have a Core data entity called day that has a to-one relationship with another entity named spot named spotTable.
I fetched a day record and i want to access the spot object related to my day instance i accessed it like this:
self.spotTable = [self.day valueForKey:#"spotTable"];
but when i print the spotTable object to the console i get that the data is faulted:
2012-04-28 13:33:35.161 The Parking Lot[18800:fb03] SpotTable: <NSManagedObject: 0x6b2b820> (entity: Spot; id: 0x6b2b200 <x-coredata://B1F7E573-BCD7-486D-8471-C3D80B891A3B/Spot/p1> ; data: <fault>)
is there a way i can fetch the data from the spotTable object?

A relationship will not be auto-fetched, because you may not need its attributes. You can manually fault it, or you can use -setRelationshipKeyPathsForPrefetching. See the documentation for NSFetchRequest:
https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/CoreDataFramework/Classes/NSFetchRequest_Class/NSFetchRequest.html

Related

Storing user data in Google Cloud Datastore as an Entity Group

I am trying to find the best way to store a user in google datastore (using nodejs). I have the userId and a userData object:
userId: "some-random-string"
userData: {
info: {
name: "name",
email: "test#email.com"
},
profile: {
username: "user",
status: "using"
},
stats: {
stuffDone: 12,
stuffNotDone: 20
},
inventory: {
money: 100,
items: ["first", "second", "third"]
}
}
I know I can store all this as a single entity but would it be worth it to split it up into an entity group if I will be updating all the nested objects separately (info, profile, stats, inventory).
So I would have the root entity (that probably wouldn't exist):
datastore.key(["Users", userId])
then I would create 4 children to store the userData:
datastore.key(["Users", userId, "UserData", "Info"); --> userData.info
datastore.key(["Users", userId, "UserData", "Profile"); --> userData.profile
datastore.key(["Users", userId, "UserData", "Stats"); --> userData.stats
datastore.key(["Users", userId, "UserData", "Inventory"); --> userData.inventory
Only the user would be updating the data so contention should not be an issue. Once the user is created I wouldn't need to update more than one child at a time.
So say the stats is updated every minute, I can just update it directly with the key:
datastore.key(["Users", userId, "UserData", "Stats");
Would this be the best practice to split it up instead of rewriting the whole user object to a single entity and have to rewrite all the indexes?
With the entity group I can still query all the user data at once with:
query = datastore.createQuery().hasAncestor(datastore.key(["Users", userId]));
Then I would just need to process it to get it back into the userData object above. I would only need to do this once when the user logs in, all other times I would need to get user data it would only be a single child and I could just get the child by key.
If I shouldn't be using an entity group like this then I could do the same thing by storing each part of the user in separate entities like:
datastore.key(["UsersInfo", userId); --> userData.info
datastore.key(["UsersProfile", userId); --> userData.profile
datastore.key(["UsersStats", userId); --> userData.stats
datastore.key(["UsersInventory", userId); --> userData.inventory
Then I could still update them individually but I think would be more taxing to get all the data since I would need to do 4 queries instead of an ancestor query.
Would these entity groups or multiple entities be necessary if I am only updating the userData.stats and userData.profile around once per minute, or should I just be using a single entity. The stats and profile objects will get bigger than only a couple properties.
Splitting an entity into multiple related ones based on the property update patterns may be a good idea, especially for large entities - to avoid unnecessarily re-writing the entire entity when just a portion of it changes (with the associated increase in the duration of the update of the entity itself and of all its related indexes. See related re-using an entity's ID for other entities of different kinds - sane idea?
Placing all the entity "pieces" into the same entity group - which, as you observed, allows you to make ancestor queries to retrieve the user data, is OK as long as you respect the max 1 write/second per entire entity group. Just double-check if you can safely assume that the query results come in a specific order, otherwise you may need to take steps to ensure each result goes to the right object.
Using separate, non-ancestor related entity "pieces" allows a higher overall write rate than the split with ancestor: max 1 write/second per each entity. And technically you don't need to do 4 queries to retrieve the entities, but 4 key lookup operations, see Retrieving an entity.
But splitting the entity can also increase your datastore costs: the single read/write operation for a single entity will be multiplied by the number of "pieces" in which the entity was split - in your case 4 if you read/write all of them together.
So you'll have to balance these pros and cons in the context of your application.

Restkit: when a foreign key is set to null the relationship in Core Data is not reset

Basically when a foreign key becomes null (after it was set to a value) the relationship in core data is not reset.
Take as an example the following one-to-many relationship:
contact <<---> company (contact has one company, company has many contacts)
Which is mapped in both directions with the following methods from Restkit:
RKRelationshipMapping *contactCustomerRelationshipMapping = [RKRelationshipMapping relationshipMappingFromKeyPath:#"contacts" toKeyPath:#"hasContacts" withMapping:contactResponseMapping];
[customerResponseMapping addPropertyMapping:contactCustomerRelationshipMapping];
[contactResponseMapping addConnectionForRelationship:#"forCustomer" connectedBy:#{#"companyID" : #"identifier"}];
Then, assume that a contact is linked to a company both in core data and in the remote server, so the JSON returns:
company_id = 123
which is correctly mapped to the relationship in Core Data.
Although when the relationship is null-ed out the returning JSON in response of a GET contact returns:
'contact': {
....
address = "20 Wordworth Ave";
city = "<null>";
"company_id" = "<null>";
...
}
The company_id is then set correctly in the core data entity but the relationship connection mapper then does not delete the reference to the company with id 123 via the relationship. So it seems like Restkit is not applying the null value of the foreign key to the relationship in Core Data.
I have verified that this happens only when company_id is reset to null and not when the value is changed to another company_id.
Let me know if you have any suggestion on how to solve the issue.
(Right now I am thinking to implement the setter for company_id and manually reset the relationship when it's null)
Thanks a lot!
I am using the latest Restkit development branch (which is tagged as 0.21.0 - currently the lastest release is 0.20.3 but blake watters told me that the development branch has already been tagged but he did not have the time to prepare docs)
I am actually using cocoapods and included the latest dev release with the line:
pod 'RestKit', :head
Your workaround should be doable.
This could be classed as a bug in RestKit. As such you'd be better off raising it as an issue. You can also looking at adding it as a feature.
It's possible that you could use fetchRequestBlocks in order to provide RestKit with the information required to handle this, but this would result in the object being deleted which may not be what you want.

Core Data Managed Object one-to-many relationship insert/update save

Lets assume I have person->phones relationship (One to many of course). Initial insert save is working correctly where I do:
if (does not exist) {
user = (Member *)[NSEntityDescription insertNewObjectForEntityForName:#"Person" inManagedObjectContext:ctx];
} else {
searchObjectsForEntity:#"Person" withPredicate:pred andSortKey:nil andSortAscending:NO andContext:ctx];
Should this be replaced with just one insertNewObjectForEntityForName which would either insert or get existing?
Next, I need to create my phones objects and add them to my Person which I do with something like this:
NSManagedObject* mo=nil;
Phone* phone = (Phone *)[NSEntityDescription insertNewObjectForEntityForName:#"Phone"
inManagedObjectContext:ctx];
[mutableSetOfPhones addObject:mo];
user.phones = phones;
So I create a new instance of phone managed object add it to a set and add it to person, after that I save.
All this is good except when I use the same code to re-save Person instance i.e. edit/insert/delete a phone or any other modifications to user data. Old records of phones remain in the DB and are no longer associated with any Person.
What is the right approach of doing this? Do I need to iterate through user.phones to see edits/deletes by some id? Should I just delete older instances prior to saving updated records (much simpler)? What is the recommended approach, maybe I am doing something completely incorrect?

Envers #ManyToMany subquery

I have an audited entity A. Entity A holds field 'name' and a collection of entities B (annotated as Many-to-many relationship). I created an instance of A, defined name, collection of entities B and save all it into DB. This is revision #1. Then I changed name of A and update it in DB. This is revision #2.
I use the following method to get all entities of class A at revision #2
List<A> list = getAuditReader().createQuery().forEntitiesAtRevision(A.class, 2)
.add(AuditEntity.revisionNumber().eq((int) revisionId)).getResultList();
I get entity A at revision #2, but Envers also fetches collection of entities B related to this A from revision #1. Here an example of query used by Envers:
SELECT a_b_aud.a_id, a_b_aud.b_id
FROM a_b_aud CROSS JOIN b_aud
WHERE a_b_aud.b_id=b_aud.id
AND b_aud.rev=(SELECT max(b_aud2.rev)) FROM b_aud AS b_aud2 WHERE b_aud2.rev<=2 AND b_aud.id=b_aud2.id)
AND a_b_aud.rev=(SELECT max(a_b_aud2.rev)) FROM a_b_aud AS a_b_aud2 WHERE a_b_aud2.rev<=2 AND a_b_aud.a_id=a_b_aud2.a_id AND a_b_aud.b_id=a_b_aud2.b_id)
But actually I need NULL as a collection of entities B in case of there were no changes for it at revision #2 (because of performance issue).
There are two subselects in this query. And if we have more then one collection of entities related to A (C, D, E, F) and for about 100 thousands rows for each b_aud and a_b_aud the query above takes a lot of time.
I defined entity B as not audited (i.e. did not add #Audited annotation into B) and defined A B relation by the following:
#ManyToMany
#Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE})
#JoinTable(name = "a_b", joinColumns = #JoinColumn(name = a_id))
#Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
public Set<B> getBs();
It fixes first SUBSELECT.
But I can not find standard solution to not query B's if it do not exist for requested revision (in my case #2). So the query should look like:
SELECT a_b_aud.a_id, a_b_aud.b_id
FROM a_b_aud CROSS JOIN b_aud
WHERE a_b_aud.b_id=b_aud.id b_aud.rev=2 AND a_b_aud.rev=2
The only solution I found is using native sql query and to execute it using hibernate template. Then convert result values into entity A using ResultTransformer.
Could anybody help with this issue? Is there a standard configuration/annotation I need to add to avoid second SUBSELECT?
There's no option in Envers not to load related entities when requested. Not however, that the B entities are always loaded lazily (regardless of the annotations on the relation), so if you don't want to execute the query which loads them, simply do not access that field.
If you want better read performance, you may also want to look at the validity audit strategy, see http://docs.jboss.org/hibernate/core/4.1/devguide/en-US/html/ch15.html#d5e4085. It has faster reads, but slower writes.

Loading related entities when dealing with Models and Collections from Backbone to Express / Mongoose

I have a UserService object that is essentially a Service with additional configuration parameters and is attached to a User. In my View I would like to render a list of these UserServices however the model is formed as such:
UserService = Backbone.Model.extend({
defaults: {
id: 0,
user_id: 0, // This needs to reference the user object somehow
service_id: 0, // This needs to reference the service object somehow
length: 216000,
price: 1000
}
});
If I bind this model to the view, what is rendered ends up being the service_id instead of the parameter I need to render: service.name.
My questions are:
What should be stored in the UserService model at service? The full service object? Mongoose ID? Some other ID? (Please specify a suggestion)
Where should I get the information for this service.name / When should I pull the Service object to get that information? It would be nice to be able to do service.name in the view when rendering...
Is there a function to chain--upon loading the model, load related models that are needed?
Overall I just need an understanding of how related models work in Backbone / Express / Mongoose.
Any help is appreciated!
Update: After doing a bit of reading I have a couple different methods I can see:
Within the constructor / initializer load the Service object into the UserService object based on the reference ID returned from the server.
My questions with that one then become... what is the reference ID? Where do I put the newly retrieved object into, possibly in place of the ID?
Use the toJSON method to return an asthetic version of the UserService where it retreives the Service object and would return an object with the service name in it's place:
{
id: ???,
service_name: "this was retrieved from the service object in the toJSON method",
length: "1 hour", // converted from within the toJSON method
price: 10.00 // converted from cents to dollars in the toJSON method
}
Or maybe a combination? Thoughts?
Parse models handle loading related entities well, there is also library called Backbone Relational that can help with this.
Otherwise, my best recommendation is to store the object's ID and fetch the related entity upon success of fetching the first entity.
Anyone needing a code example just comment here and I'll see what I can come up with.

Resources