Start a new topic

Relational Data - Invalid type in JSON write (KCSKinveyRef)

I am new to Kinvey but I am experiencing difficulties using Relational Data


- I am using KinveyKit-1.40.4

- I am following the steps outlined in http://devcenter.kinvey.com/ios/guides/datastore

- I am using KCSLinkedAppdataStore

- I have confirmed that both entities are configured correctly and save individually but when I attempt to update them with a relationship (single or multiple) I get an exception.


'NSInvalidArgumentException', reason: 'Invalid type in JSON write (KCSKinveyRef)'


Can anyone suggest a possible solution? I am missing an important step?


2 people have this question

I just wanted to follow up on this guys... We are looking to address this issue in the present sprint, it slipped from the last one due to competing priorities.   I'm going to see if I can get this prioritized to be released this week if at all possible.   


Thanks,


2 people like this

Hello Everyone,


The problem that Damien is referencing in his last update on March 28, 2016, has been fixed in the iOS SDK release 1.40.6 which can be found and downloaded at the following URL.


http://devcenter.kinvey.com/ios/downloads


This fix is identified in the download notice as:


"Bug fix: Handling arrays for Relational Data using KCSLinkedAppdataStore"


Please let us know if you have any difficulties with this update.


Regards,


Billy Gee



2 people like this

I have update to 1.40.5 and I am able to add singular entity relationships e.g. event.invitee = firstInvitation however when I attempt to map to an NSMutableSet of multiple entities e.g. event.invitees = [firstInvitation] I receive the error


'Invalid type in JSON write (KCSKinveyRef)'


Do I need to change to configuration of kinveyPropertyToCollectionMapping,  kinveyObjectBuilderOptions or referenceKinveyPropertiesOfObjectsToSave to solve this issue?


Thanks


P.S. Do anyone have a generic sample projects that demonstrates how to setup this up?


1 person likes this

All,


Using code provided from a few people here (Edward / D Chaudhari, Richard) we have been able to recreate the issue that you guys described above and have filed this as a ticket to be addressed moving forward.   I believe our current development sprint begins today.  I am uncertain of other items that would be of competing priority, but I would expect a patch to our SDK in no longer than 2 weeks time (the end of the sprint) and very likely before then.


Thanks again for your help.


1 person likes this

1.40.5 seems to have fixed relational data for 1-to-1 relationships e.g. user: KCSUser = KCSUser.activeUser() the problem occurs when attempting to store multiple references in an array e.g. users: [KCSUser] = [KCSUser.activeUser()


static override func kinveyPropertyToCollectionMapping() -> [NSObject : AnyObject]! {

 return ["user" : KCSUserCollectionName, "users" : KCSUserCollectionName]

 }




1 person likes this

Damien:


I realize you're responding to D Chaudhari's message and the world doesn't revolve around me, but I find it rather frustrating that my questions and code examples are being ignored. You have mentioned the example in the dev center and the dev center's explanation of limitations, but as I've posted several times, I have copied that example and run it in a sample app, and it does not work.


Here is the Event class, copied directly from the example: https://git.io/v2j2b

Here is the Invitation class, copied directly from the example: https://git.io/v2jas

And here is my attempt to save them in a one-many relationship: https://git.io/v2jai


I realize that my attempt to save might be flawed, but I can't figure out why, and it would be wonderful if someone could explain it. It would help me and, I think, the other developers following this thread.


It would also be nice if someone could explain why my saves fail when the referenced objects have properties that are KinveyRefs. I include well-commented examples of that in that GitHub repo.


Thanks


1 person likes this

Richard:  We really discourage against heavy leveraging of relational data and strongly encourage the use of Flat architectures that encourage normalizing your objects rather than using relational querying.  Since the schema can change at any time by modifying your queries having multiple tables and foreign key constraints becomes really unnecessary, and thus relational data being saved into a single object rather than across multiple tables becomes both sensible and easier than trying to use KinveyReferences. 


That said, there are hard limits on how many KinveyRef's can be resolved in a single query (I think it's 99), are you sure that you're not going above that?


Thanks,  


1 person likes this

I've also been having trouble getting "to-many" relationships to work in my Swift project. In order to get to the bottom of the situation, I created a project with KinveyKit 1.40.5, using the Events and Invitations example from the Data Store guide.


I created exact copies of the Event and Invitation code from the example, except for the use of "private" in the override methods, which is no longer used in Swift (you'd use "internal" for subclass-only access).


I discovered there is at least one bug in KinveyKit: The mapping system doesn't pick up properties defined as `NSInteger?` (the Invitation.status property, for example). When you try to save, you get the error: "Entity does not have property 'status' as specified in hostToKinveyPropertyMapping", which is especially annoying when you're looking right at it in your hostToKinveyPropertyMapping. My current workaround is to change the property to a `String?`.


Once I did that, I was able to save entities with a to-one relationship. For example, if I instantiate an event, and an invitation, and I set `invitation.event = event`, I am able to save succesfully, and both the event and invitation are persisted in my Kinvey db.


However, if I try setting the to-many property of the event, it fails, e.g. `event.invitations = NSMutableSet(array: [invitationA, invitationB]`.


Like Richard, I get: "Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Invalid type in JSON write (KCSKinveyRef)'... libc++abi.dylib: terminating with uncaught exception of type NSException"


Here are links to my code. As I said, it's mostly copied directly from the tutorial. Can anyone see a problem with the way I'm instantiating and saving the entities?


Event class: https://gist.github.com/elopinto/a53424986e9fbfe18146

Invitation class: https://gist.github.com/elopinto/4387e72c17ae5b825fec

Saving from VC: https://gist.github.com/elopinto/a3c38bd1a0a4f9ace5d9

Hi there Richard, 


There was a bug in version 1.40.4 of our iOS library which is updated in the most recent update.   Can you please give that a shot and try it out?


Thanks,


http://devcenter.kinvey.com/ios/downloads

Hi , each time when I use KCSLinkedAppdataStore in  release 1.40.6  I get next exception 


2016-04-07 11:21:19.515 BooksAround[2315:685126] *** Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection <__NSDictionaryM: 0x16193b9d0> was mutated while being enumerated.'

*** First throw call stack:

(0x18146ee38 0x180ad3f80 0x18146e86c 0x100431cf4 0x100431f2c 0x10043204c 0x1003c9ea0 0x1003c9fd0 0x1003b8e00 0x1003b99f8 0x1003b9840 0x1003ba3c4 0x1003bb534 0x100438754 0x181e2a904 0x10057da3c 0x10058a554 0x10058172c 0x10058c66c 0x10058c364 0x1810d1470 0x1810d1020)

libc++abi.dylib: terminating with uncaught exception of type NSException


In 1.40.5 it worked ok

Best Regards

Wood


Wood Wayfarer:


That might have been a bug in version 1.40.6 of the SDK, rather than directly related to the relational data issue. I also received that error when making queries after upgrading from 1.40.5 to 1.40.6. Upgrading to 1.40.7 solved the problem.


See this thread: https://support.kinvey.com/support/discussions/topics/12000002270.

I am still getting the exact same error when trying to create related objects and save. I am using 1.40.5 as well.

 This is my code snippet: KCSQuickle has an array to KCSQuickleItems -- both are collections in by Data Store.

class KCSQuickle: NSObject {
    
    static let collectionName = "Quickles"
    static let titleField = "title"
    static let itemsField = "items"
    
    var entityId: String?               // Kinvey entity _id
    var title: String                   // Title of the quickle
    var contributors: [KCSUser]?        // Array of contributors who liked
    var likes: [KCSUser]?               // Array of users who liked
    var metadata: KCSMetadata?          // Create, Updated and Creator
    var items: [KCSQuickleItem]      // Referenced of type KCSQuickleItem

    
    private override init() {
        title = ""
        items = [KCSQuickleItem]()
        super.init()
    }
    
    convenience init(titleString: String) {
        self.init()
        title = titleString
    }
   
    override func hostToKinveyPropertyMapping() -> [NSObject : AnyObject]! {
        return [
            "entityId" : KCSEntityKeyId,
            "title" : KCSQuickle.titleField,
            "items" : KCSQuickle.itemsField,
            "metadata" : KCSEntityKeyMetadata,
        ]
    }
    
    static override func kinveyPropertyToCollectionMapping() -> [NSObject : AnyObject]! {
        return [
            // backend to collection name
            KCSQuickle.itemsField : KCSQuickleItem.collectionName
        ]
    }
    
    static override func kinveyObjectBuilderOptions() -> [NSObject : AnyObject]! {
        return [
            KCS_REFERENCE_MAP_KEY : [
                // property name to object
                "items" : KCSQuickleItem.self
            ]
        ]
    }
    
    override func referenceKinveyPropertiesOfObjectsToSave() -> [AnyObject]! {
        // array of backend property names to save
        return [ KCSQuickle.itemsField ]
    }
}



class KCSQuickleItem: NSObject {
    
    static let collectionName = "QuickleItem"
    static let itemDescriptionField = "item_description"
    
    var entityId: String?           // Kinvey entity _id
    var itemDescription: String?

    override func hostToKinveyPropertyMapping() -> [NSObject : AnyObject]! {
        return [
            "entityId" : KCSEntityKeyId,
            "itemDescription" : KCSQuickleItem.itemDescriptionField
        ]
    }

 I try to save it as:


 

let store = KCSQuickle.getLinkedStore()
                        store.saveObject(self.quickle, withCompletionBlock: { (saveResults, saveError) -> Void in
if (saveError == nil) {
// do stuff
}
}, withProgressBlock: nil)

 

D. Chaudhari:


Just so I can make sure that I understand -- when you are saving this relational data, how are you going about saving it?  You would need to specify all the relevant information for it (collection, id, etc) like you would any normal object.   Also:  If you are pulling references that have "null" data that could present issues as well, as that's not an intended usage of the library.   Either you have associated data, or you don't.


Can you help me understand the use case of mapping null data to an object relation?


Also, we give an example of a 1:many relationship in our dev center.  In the last example before our Limitations on Relational data:  http://devcenter.kinvey.com/ios/guides/datastore#limitations


Thanks,

All:


Please see this example whipped up by our iOS developer Victor.  This shows how to map a relation in Kinvey:


https://github.com/KinveyApps/iOS-Sample-Relational-Data


Please let me know if you have any other questions.

Login or Signup to post a comment