Realm-cocoa: Please help me understand why there is an unexpected existing value in my primary key.

Created on 16 Dec 2014  路  9Comments  路  Source: realm/realm-cocoa

I am trying to make Article objects that contain many Paragraph objects that contain many Sentence objects that contain many Word objects. I am able to accomplish making an Article that contains Paragraphs and I am able to make a Paragraph that contains Sentences that contain Words, but I am unable to figure out why I can't do the whole multidimensional relationship.

In my classes below, at this line:

    self.sentences.addObject(sentenceObject) // this is the line of code that causes the exception

I am getting the following exception:

Terminating app due to uncaught exception 'RLMException', reason: 'Can't set primary key property 'sentenceContent' to existing value ''.'

Here are my classes:

class Article: RLMObject
{
dynamic var title = ""
dynamic var articleContent = ""
override class func primaryKey() -> String
{
    return "articleContent"
}
dynamic var paragraphs = RLMArray(objectClassName: Paragraph.className())
dynamic var viewed = false
dynamic var dateAdded = NSDate()

convenience init(content: String)
{
    self.init()
    self.articleContent = content
    let paragraphsArray = splitArticleIntoParagraphs(content)
    for paragraphString in paragraphsArray
    {
        var paragraphObject = Paragraph(content: paragraphString)
        self.paragraphs.addObject(paragraphObject)
        paragraphObject.article = self
    }
}
}


class Paragraph: RLMObject
{
dynamic var paragraphContent = ""
override class func primaryKey() -> String
{
    return "paragraphContent"
}
dynamic var article: Article?// = RLMArray(objectClassName: Sentence.className())
dynamic var sentences = RLMArray(objectClassName: Sentence.className())

convenience init(content: String)
{
    self.init()
    self.paragraphContent = content
    let sentenceArray = splitParagraphsIntoSentences(content)
    for sentenceString in sentenceArray
    {
        var sentenceObject = Sentence(content: sentenceString)
        sentenceObject.paragraphs.addObject(self)
        self.sentences.addObject(sentenceObject) // this is the line of code that causes the exception
    }
}
}

class Sentence: RLMObject
{
dynamic var words = RLMArray(objectClassName: Word.className())
dynamic var paragraphs = RLMArray(objectClassName: Paragraph.className())
dynamic var machineTranslation = ""
dynamic let dateAdded = NSDate()
dynamic var sentenceContent = ""

override class func primaryKey() -> String
{
    return "sentenceContent"
}
convenience init(content: String)
{
    self.init()
    self.sentenceContent = content
    let wordArray = splitSentenceIntoWords(content)
    for wordString in wordArray
    {
        let searchedWord = Word.objectsWhere("simplified == '\(wordString)'")
        if searchedWord.firstObject() != nil
        {
            self.words.addObject(searchedWord.firstObject() as RLMObject)
        }
    }
}
}

class Word: RLMObject
{   
dynamic var simplified = ""
override class func primaryKey() -> String
{
    return "simplified"
}
    dynamic var traditional = ""
dynamic var pinyin = RLMArray(objectClassName: Pinyin.className())
dynamic var englishDefinitions = RLMArray(objectClassName: Definition.className())
dynamic var sentences = RLMArray(objectClassName: Sentence.className())
dynamic var date = NSDate()
}

I initialize an Article like this:

        var articleContent = removeSpaces(newArticleTextField.text)
        var newArticle = Article(content: articleContent)
        newArticle.title = articleTitleField.text

        var Realm = RLMRealm.defaultRealm()
        Realm.beginWriteTransaction()
        Realm.addObject(newArticle)
        Realm.commitWriteTransaction()

Can you help me see where I am unexpectedly attempting to add a duplicate value?

T-Help

Most helpful comment

Or you could just use self.sentences.addObject(sentenceObject, update: true)

All 9 comments

When you call addObject in the crashing line of code, you are passing in a Sentence object not yet added to the Realm. So when you add your Sentence object to your Paragraph a call is made internally to add the object to the Realm - but in some cases an object with the same primary key already exists causing an exception.

Two solutions:

  • Remove the primary key for Sentence. Then you can have duplicate sentence content using your existing code. All you need to do this is remove the primaryKey method on your sentence object.
  • Look up sentences before adding them. If the sentence doesn't already exist in the Realm then add it to the Realm, and add the persisted object to your array.

Shouldn't this just be a link to the sentence? If that is true then there shouldn't be a problem with duplicate values because it is just a link. Each Paragraph can have many Sentence object links (even if they are repeated sentences) and each Sentence object can have many Paragraph object links. Am I thinking wrong?

If you define a primary key, you can not have duplicate values across all object of that type. When you add a link you are creating a new object of that type which is why you have the problem. If you remove your primary key from Sentence (which doesn't seem to be needed) you will not longer have this issue.

I really appreciate your help on this.

I removed the primary key and now the console prints:

2014-12-16 11:51:54.725 MyApp[14969:548467] +[MyApp UTF8String]: unrecognized selector sent to class 0x2853f8
2014-12-16 11:51:54.730 MyApp[14969:548467] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+[MyApp.Sentence UTF8String]: unrecognized selector sent to class 0x2853f8'
** First throw call stack:
(
0 CoreFoundation 0x009e9946 *
exceptionPreprocess + 182
1 libobjc.A.dylib 0x023f9a97 objc_exception_throw + 44
2 CoreFoundation 0x009f1465 +[NSObject(NSObject) doesNotRecognizeSelector:] + 277
3 CoreFoundation 0x0093a3e7 ___forwarding_
+ 1047
4 CoreFoundation 0x00939fae _CF_forwarding_prep_0 + 14
5 MyApp 0x00139656 _Z35RLMRealmSetPrimaryKeyForObjectClassP8RLMRealmP8NSStringS2_ + 351
6 MyApp 0x001121e5 _Z20RLMRealmCreateTablesP8RLMRealmP9RLMSchemab + 3821
7 MyApp 0x0010b29e -[RLMMigration migrateWithBlock:version:] + 145
8 MyApp 0x00133ede +[RLMRealm migrateRealm:] + 216
9 MyApp 0x00131677 +[RLMRealm realmWithPath:readOnly:inMemory:dynamic:schema:error:] + 1128
10 MyApp 0x00131148 +[RLMRealm realmWithPath:readOnly:error:] + 80
11 MyApp 0x00131077 +[RLMRealm defaultRealm] + 87
12 MyApp 0x000e69a1 _TFC11 MyApp 11AppDelegate11applicationfS0_FTCSo13UIApplication29didFinishLaunchingWithOptionsGSqGVSs10DictionaryCSo8NSObjectPSs9AnyObject____Sb + 353
13 MyApp 0x000e6cbe _TToFC11 MyApp 11AppDelegate11applicationfS0_FTCSo13UIApplication29didFinishLaunchingWithOptionsGSqGVSs10DictionaryCSo8NSObjectPSs9AnyObject____Sb + 542
14 UIKit 0x011f697c -[UIApplication _handleDelegateCallbacksWithOptions:isSuspended:restoreState:] + 291
15 UIKit 0x011f7687 -[UIApplication _callInitializationDelegatesForMainScene:transitionContext:] + 2869
16 UIKit 0x011fac0d -[UIApplication _runWithMainScene:transitionContext:completion:] + 1639
17 UIKit 0x012137d0 __84-[UIApplication _handleApplicationActivationWithScene:transitionContext:completion:]_block_invoke + 59
18 UIKit 0x011f981f -[UIApplication workspaceDidEndTransaction:] + 155
19 FrontBoardServices 0x0507c9de __37-[FBSWorkspace clientEndTransaction:]_block_invoke_2 + 71
20 FrontBoardServices 0x0507c46f __40-[FBSWorkspace _performDelegateCallOut:]_block_invoke + 54
21 FrontBoardServices 0x0508e425 __31-[FBSSerialQueue performAsync:]_block_invoke + 26
22 CoreFoundation 0x0090d1c0 __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 16
23 CoreFoundation 0x00902ad3 __CFRunLoopDoBlocks + 195
24 CoreFoundation 0x00902238 __CFRunLoopRun + 936
25 CoreFoundation 0x00901bcb CFRunLoopRunSpecific + 443
26 CoreFoundation 0x009019fb CFRunLoopRunInMode + 123
27 UIKit 0x011f91e4 -[UIApplication _run] + 571
28 UIKit 0x011fc8b6 UIApplicationMain + 1526
29 MyApp 0x000e729e top_level_code + 78
30 MyApp 0x000e72db main + 43
31 libdyld.dylib 0x03115ac9 start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)

Since you changed your model you need to delete your Realm file.

Or you could just use self.sentences.addObject(sentenceObject, update: true)

This problem happens with List<T> too, this class doesn't have any method that I can force the update of values, any ideia?

It happened when I tried to use the method append<S: Sequence>(objectsIn objects: S) of List.swift provided by Realm.

2017-04-01 10:56:03.764 My_Little_Pony[60800:5234403] *** Terminating app due to uncaught exception 'RLMException', reason: 'Can't create object with existing primary key value '36'.'
*** First throw call stack:
(
    0   CoreFoundation                      0x000000010ba05d4b __exceptionPreprocess + 171
    1   libobjc.A.dylib                     0x000000010f06721e objc_exception_throw + 48
    2   Realm                               0x000000010cee81be _ZL23createOrGetRowForObjectIZ19RLMAddObjectToRealmE3$_0EmRK12RLMClassInfoT_bPb + 334
    3   Realm                               0x000000010cee75a5 RLMAddObjectToRealm + 677
    4   Realm                               0x000000010d023038 -[RLMRealm addObject:] + 40
    5   Realm                               0x000000010ceba572 _ZL19validateObjectToAddP16RLMArrayLinkViewP9RLMObject + 450
    6   Realm                               0x000000010ceb9bf8 _ZL15RLMInsertObjectP16RLMArrayLinkViewP9RLMObjectm + 168
    7   Realm                               0x000000010ceb9b08 -[RLMArrayLinkView addObject:] + 56
    8   RealmSwift                          0x000000010c355277 _TFC10RealmSwift4List6appenduRd__s8SequencexzWd__8Iterator7Element_rfT9objectsInqd___T_ + 375

@ppamorim List.append(_:) will "promote" unmanaged Realm objects that you pass it to managed objects by creating them in the Realm. There's no variant of List.append(_:) that will "create or update" the unmanaged objects you pass in to it.

In the future, please use Stack Overflow for general usage questions about Realm, where either our support team or the community may answer.

For bug reports or feature requests, please file a new issue taking care to fill out the new issue template.

Comments on issues that have been closed for a long time are easily missed and often lack very important information. I'll be closing this conversation now.

Was this page helpful?
0 / 5 - 0 ratings