域-不能创建具有现有主键值的对象。

时间:2022-03-08 20:41:25

I have a object Person with many dogs. App has separate page where it shows just dogs and other page where it shows person's dogs

我有一个有很多狗的对象。应用程序有单独的页面,它显示狗和其他页面,在那里它显示了人的狗。

My model is as follows

我的模型如下。

class Person: Object {
    dynamic var id = 0
    let dogs= List<Dog>()

    override static func primaryKey() -> String? {
        return "id"
    }
}

class Dog: Object {
    dynamic var id = 0
    dynamic var name = ""

    override static func primaryKey() -> String? {
        return "id"
    }
}

I have persons stored in Realm. Person has detail page where we fetch and show his dogs. If dog already exist, I update latest info for that dog and add it to person's dog list else create new dog, save it and add it to persons list. This works in coredata.

我有个人收藏在王国里。人有详细的页面,我们取回和显示他的狗。如果狗已经存在,我将更新狗的最新信息,并将它添加到人的狗列表中,创建新狗,保存它并将它添加到人员列表中。这在coredata工作。

// Fetch and parse dogs
if let person = realm.objects(Person.self).filter("id =\(personID)").first {
    for (_, dict): (String, JSON) in response {
        // Create dog using the dict info,my custom init method
        if let dog = Dog(dict: dict) {
            try! realm.write {
                // save it to realm
                realm.create(Dog, value:dog, update: true)
                // append dog to person
                person.dogs.append(dog)
            }
        }
    }
    try! realm.write {
        // save person
        realm.create(Person.self, value: person, update: true)
    }
}

On trying to update person with his dogs,realm throws exception Can't create object with existing primary key value

在试图用他的狗更新人员时,realm抛出异常不能创建具有现有主键值的对象。

1 个解决方案

#1


18  

The problem here is that even though you're creating a completely new Realm Dog object, you're not actually persisting that one to the database, and so when you call append, you're trying to add a second copy.

这里的问题是,即使您创建了一个全新的域Dog对象,您实际上并没有将该对象持久化到数据库中,因此当您调用append时,您正在尝试添加第二个副本。

When you call realm.create(Dog, value:dog, update: true), if an object with that ID already exists in the database, you're simply updating that existing object in with the values in the dog instance you created, but that dog instance is still an independent copy; it's not the Dog object in the database. You can confirm this by checking if dog.realm is equal to nil or not.

当你叫领域。创建(Dog, value: Dog, update: true),如果数据库中已经存在该ID的对象,那么只需在创建的Dog实例中更新现有的对象,但Dog实例仍然是独立的副本;它不是数据库中的Dog对象。你可以通过检查狗狗来确认。域等于nil。

So when you call person.dogs.append(dog), because dog is not already in the database, Realm tries to create a whole new database entry, but fails because there is already a dog with that ID.

因此,当您调用person.dogs.append(dog)时,因为dog还没有在数据库中,所以Realm试图创建一个全新的数据库条目,但是失败了,因为已经有了带有该ID的狗。

If you want to append that dog object to a person, it'll be necessary to query Realm to retrieve a proper dog object that's referencing the entry in the database. Thankfully this is really easy with Realm objects backed by primary keys since you can use the Realm.object(ofType:forPrimaryKey:) method:

如果您想要将dog对象附加到person,那么就需要查询域来检索一个适当的dog对象,该对象引用数据库中的条目。幸运的是,使用主键支持的领域对象非常简单,因为您可以使用Realm.object(ofType:forPrimaryKey:)方法:

if let person = realm.object(ofType: Person.self, forPrimaryKey: "id") {
    for (_, dict): (String, JSON) in response {
        //Create dog using the dict info,my custom init method
        if let dog = Dog(dict: dict)
        {
            try! realm.write {
                //save it to realm
                realm.create(Dog, value: dog, update: true)
                //get the dog reference from the database
                let realmDog = realm.object(ofType: Dog.self, forPrimaryKey: "id")
                //append dog to person
                person.dogs.append(realmDog)
            }
        }
    }
    try! realm.write {
        //save person
        realm.create(person .self, value: collection, update: true)
    }
}

#1


18  

The problem here is that even though you're creating a completely new Realm Dog object, you're not actually persisting that one to the database, and so when you call append, you're trying to add a second copy.

这里的问题是,即使您创建了一个全新的域Dog对象,您实际上并没有将该对象持久化到数据库中,因此当您调用append时,您正在尝试添加第二个副本。

When you call realm.create(Dog, value:dog, update: true), if an object with that ID already exists in the database, you're simply updating that existing object in with the values in the dog instance you created, but that dog instance is still an independent copy; it's not the Dog object in the database. You can confirm this by checking if dog.realm is equal to nil or not.

当你叫领域。创建(Dog, value: Dog, update: true),如果数据库中已经存在该ID的对象,那么只需在创建的Dog实例中更新现有的对象,但Dog实例仍然是独立的副本;它不是数据库中的Dog对象。你可以通过检查狗狗来确认。域等于nil。

So when you call person.dogs.append(dog), because dog is not already in the database, Realm tries to create a whole new database entry, but fails because there is already a dog with that ID.

因此,当您调用person.dogs.append(dog)时,因为dog还没有在数据库中,所以Realm试图创建一个全新的数据库条目,但是失败了,因为已经有了带有该ID的狗。

If you want to append that dog object to a person, it'll be necessary to query Realm to retrieve a proper dog object that's referencing the entry in the database. Thankfully this is really easy with Realm objects backed by primary keys since you can use the Realm.object(ofType:forPrimaryKey:) method:

如果您想要将dog对象附加到person,那么就需要查询域来检索一个适当的dog对象,该对象引用数据库中的条目。幸运的是,使用主键支持的领域对象非常简单,因为您可以使用Realm.object(ofType:forPrimaryKey:)方法:

if let person = realm.object(ofType: Person.self, forPrimaryKey: "id") {
    for (_, dict): (String, JSON) in response {
        //Create dog using the dict info,my custom init method
        if let dog = Dog(dict: dict)
        {
            try! realm.write {
                //save it to realm
                realm.create(Dog, value: dog, update: true)
                //get the dog reference from the database
                let realmDog = realm.object(ofType: Dog.self, forPrimaryKey: "id")
                //append dog to person
                person.dogs.append(realmDog)
            }
        }
    }
    try! realm.write {
        //save person
        realm.create(person .self, value: collection, update: true)
    }
}