I have an ios 5 app which does not create any data - it simply makes a GET call to a REST webservice and populates the sqlite database with those records. The initial GET works great when there are no records in the local database. However when I make subsequent calls, I will only be returning a subset of records whose data has changed since the last GET. But what is happening is that the records are just being added again, not updating the existing records.
I have an ID field which is the primary key (or should be) and when a record comes in whose ID already exists, I want that data to be updated. If that ID does not exist, it should be an insert.
I didn't see a way to set my ID field as a 'primary key' in the datamodel in XCode. I tried doing this in my didFinishLaunchingWIthOptions method:
userMapping.primaryKeyAttribute = #"id";
But that alone didn't really seem to do anything.
This is my call to actually perform the GET:
// Load the object model via RestKit
[objectManager loadObjectsAtResourcePath:[#"/synchContacts" appendQueryParams:params] delegate:self];
Which seems to do everything automagically. I am lost at this point as to where I should be putting logic to check to see if the ID exists, and if so do an update vs an insert, or what.
As of the latest RESTKit version (0.23) you can define the primary key like this:
[_mapping addAttributeMappingsFromDictionary:#{ #"id" : #"objectId", #"name" : #"name" }];
[_mapping setIdentificationAttributes:#[ #"objectId" ]];
Whereas objectId is you primary key on the core data object.
You seem to be doing it correctly and when your didLoadObjects callback happens you should be able to query Core Data for the objects you need.
You might be having an issue with the way your fetch requests are being set up. With the latest RestKit you can use RKObjectMappingProvider's
- (void)setObjectMapping:(RKObjectMappingDefinition *)objectMapping forResourcePathPattern:(NSString *)resourcePathPattern withFetchRequestBlock:(RKObjectMappingProviderFetchRequestBlock)fetchRequestBlock;
function and have the fetchRequestBlock fetch the proper data.
RestKit doesn't really handle partial update requests very well out of the box though. You might have more luck on the RestKit google group which is very active.
Quote:
I didn't see a way to set my ID field as a 'primary key' in the datamodel in XCode. I tried doing this in my didFinishLaunchingWIthOptions method:
userMapping.primaryKeyAttribute = #"id";
Keep in mind, the 'primaryKeyAttribute' is the one from your api payload, NOT a CoreData id, which CoreData manages on its own. RestKIt then maps the (invisible) CoreData primary key to the specified JSON key.
Related
I use the repositoryFactory in a custom plugin's Vue file in Shopware 6. When I save an entity I do this:
this.settingsRepository
.save(this.setting, Shopware.Context.api)
.then((result) => {
In case the person sends the form and this function is called, I want to get back the id of the setting in case the person hit's the save button again. But then the entity needs to be updated and not created. As I see from the response, there is an id, but it's in config.data -> json serialised.
How's the default way of solving this issue?
The best practice would be to re-fetch the entity after persisting it. This is because some entities may have fields that get automatically computed or indexed server-side and you'd probably always want to have the entity in its actual current state. If you're absolutely sure you don't want to fetch the entity again, you could manually set the _isNew flag to false after persisting:
this.setting._isNew = false;
This will then cause the save function to use the update instead of the create route. Keep in mind that this is actually kind of an internal property, as there is no setter for it and as already mentioned fetching the entity again is encouraged.
Also you shouldn't have to worry about the id. It should've already been generated client-side and set to the entity, when using the repository to create a new entity like that:
this.setting = this.settingsRepository.create();
I am using Azure Table Storage Rest Api to Update the entity.
If the entity has 5 columns(col1,col2,col3,col4,col5) and I am making a PUT request body something like this.
{"col1":"value"}
The rest of the columns value is set to NULL.
Is there a way to avoid it?
The reason you're seeing this behavior is because you're performing Update Entity operation which will replaces an entire entity.
If you're only interested in changing just one attribute (property), you need to use Merge Entity operation which updates an existing entity by updating the entity's properties. It does not replace the existing entity.
Simply changing your HTTP Request method to MERGE from PUT should do the trick.
I have an existing client/server, Spring boot project that uses JPA. I followed the spring-data-jpa-hazelcast-migration sample to create a Hazelcast client & server. There is existing data in a db that populates the Hazelcast Map. Each of these db entries has an Integer id which becomes the Map key. During this loadAllKeys() on the server, I populate a Set which is distributed/managed by Hazelcast; in the MemCenter UI, I see the populated Map & the Set containing the expected number of Integer keys.
Per the example mentioned above, the client application has a service which uses a HazelcastRepository to save() new entities. Since a new entity does not have an id, on the client side (where a new entity is created), I have an IdGenerator that returns nextKey(). The (distributed) Set is asked if it contains said id/key to prevent key collisions.
Then, once this save() on the client side makes its way to the server, I attempt to add the new key to the Set to avoid any collisions in the future. In doing so, I get the following exception:
Thread[hz._hzInstance_1_dev.partition-operation.thread-3,5,_hzInstance_1_dev] cannot make remote call: com.hazelcast.collection.impl.collection.operations.CollectionAddOperation{serviceName='hz:impl:setService', identityHash=1523576050, partitionId=64, replicaIndex=0, callId=0, invocationTime=-1 (1969-12-31 15:59:59.999), waitTimeout=-1, callTimeout=60000, name=com.intelligrated.hazelcast.server.maploader.ScannersMapStore_Set}
For some reason, I have not found a single example of how to handle the creation of new data especially when data already exists. The examples/test are trivial and when a new object is saved, the id is hard-coded (usually to '1').
I devised the above solution hoping that I can make this work. If there is a better way, kindly point me to an useful example.
So, I found this post helpful.
Basically, you can't have "operations" in MapStore b/c of the write through.:
"Because writethrough map store operations run on partition thread, and using another partition based operation(like Containskey) can cause deadlock. That is why we have a check and an exception there"
So, removed all the Set business from my MapStore & added necessary logic to a separate "Listener" class. The map store sends "set update events" on a Topic to which said Listener is subscribed to.
I have an iPad app, built with XCode 4.5, Storyboard, Core Data (using MagicalRecord) and iOS 6. I have two Entities, each with multiple attributes. The first entity has a one to many relationship with the second entity.
In the MagicalRecord docs, I don't see how to persist the data to the second entity; I read somewhere that Core Data generates it's own key and indexes. I know from past use of SQLite that I would need to set the key from the first entity to be able to access the second entity.
[UPDATED] Here is the modified code but it doesn't work either. I have previously selected a row in didSelectRowAtIndexedPath in another class. I assume that set the localContext. Any ideas why this is not working?
- (IBAction)saveAppointment:(UIButton *)sender {
AppointmentInfo *newAppointment = [AppointmentInfo MR_createInContext:localContext]; // create the entity
newAppointment.aStartTime = selectedStartDate;
newAppointment.aEndTime= selectedEndDate;
[localContext MR_saveNestedContexts];
}
You need to create your Entity in the proper (ie. localContext) context:
[AppointmentInfo MR_createInContext:localContext];
I found the problem... seems that I had the store setup incorrectly... I removed the parent pointer from AppointmentInfo and added the "class" information. Works like a champ now... thank you for your time, tho'.
I have an entity (several, actually) that I want to have assigned a key value based on custom logic when they're created. I know I could do it in the entity constructor, but ideally I'd like to do it as part of the data context logic for when a new entity is created.
I found how to turn off autogeneration, but what I'd rather do is replace auto generation w/ my own logic, ideally handled by the C# code (I"ve seen techniques for doing it via stored procs also, that I'd rather not use).
Is this even possible to do centrally?
Autogeneration happens on the server side and is not done by the EF. This is a setting on a table key column. So EF does not generate any keys - if autogeneration is turned on this is the database that generates keys, if autogeneration is off this is the user that is responsible for generating keys. If you don't want to generate keys when saving changes you may want to override SaveChanges and generate keys for all newly added entities.