Why entity cannot have uniqueness constraints with to-one mandatory inverse relationship?
Asked Answered
K

4

36

Why entity cannot have uniqueness constraints with to-one mandatory inverse relationship? Having two entities:

  • Person

property: name

relationship: department (to-one, non-optional)

  • Department

property: title (unique constraint)

relationship: person (to-many, optional)

Model won't compile in iOS 9, XCode 7.0.1 with misconfigured entity error:

Misconfigured Entity: Entity Department cannot have uniqueness constraints and to-one mandatory inverse relationship Person.department

Update: Question is still relevant in XCode 8.3.1.

Kyser answered 29/9, 2015 at 13:22 Comment(2)
Seems like a bug in XCode 7.0.1 – 8.3.1. Will file a radar later.Kyser
Also an issue with XCode 13.2.1Algin
A
11

Short answer:

The underlying problem is most likely caused by the sqlite standard. I'm not sure about that. How ever, it's very likely that it is because of the limitations of sqlite. I found some posts on the internet, where people had issues with multiple constraints on one table and thats most likely the reason why the two-table workaround works.

Long answer:

It's pretty late, but I hope it helps anyway.

This occurs when your Entity has an unique constraint and a mandatory relation. I guess it's because of the added unique constraint behaviors in iOS 9.0. However you can solve this in two ways:

You remove the unique constraint or make the relation optional. You could handle an optional relation in code. But it won't be a nice solution.

OR

You can use a workaround. You can have both. You can create a super class having a unique constraint. However this won't work without problems, too.

Let's you have three entities. A, B and C.

A is your super class and B is a sub class of A and C is a sub class of A, too. A has an unique constraint on it's property primaryKey. When saving instances of B and C, you can not have a B and C with the same primaryKey. Because CoreData will manage both as A.

You could change A to have two Properties:

  • int: originalPrimaryKey (NO unique constraint)
  • string: primaryKey (unique constraint)

You can now map your primaryKeys to originalPrimaryKey and when setting the originalPrimaryKey you could set the string primaryKey property to CLASS_NAME.{originalPrimaryKey}. This would allow you to have the behavior, you would expect. But you have to add a workaround for primaryKeys.

Asomatous answered 24/4, 2017 at 10:50 Comment(4)
Handling optional relation is much less effort than unwanted subclassing. Thank you for the workarounds, but the reason why is undisclosed - you just paraphrased my input, so I cannot accept this as an answer.Kyser
The underlying problem is most likely caused by the sqlite standard. I'm not sure about that, so I did not mention it. How ever, it's very likely that it is because of the limitations of sqlite. I found some posts on the internet, where people had issues with multiple constraints on one table and thats most likely the reason why the two-table workaround works.Asomatous
Thanks. I've added your comment in answer for others to find it easy.Kyser
It is shocking just how bad CoreData can be, I shouldn’t have to choose between uniqueness and enforced relationships, it’s pretty basic database stuff, even MySQL can handle that. Why am I continuing to use this when alternatives exist!Algin
I
0

I think the reason is related to merge policies. If there are entities with duplicated unique attributes, CoreData merges them by the mergy policy. If there are duplicated unique attributes, the newly created entity objects may be discarded. In that case, a one-to-one relationship to that should be nullify, which is an error for a non-optional object.

For more details, let's assume there are entities named Person and Pet. Person has a unique attribute idNumber and a one-to-many relationship to Pet. Pet also has an inverse relationship with Person as one-to-one relationship. And create duplicates of a Person object (meaning they have same idNumber) and also create corresponding related Pet objects and save them.

Now, if the merge policy is mergeByPropertyStoreTrump, the duplicates of Person will automatically merged into a stored object and all new Pet objects will be related to the stored object. It doesn't seems wrong.

However, if the merge policy is rollback, the created duplicates of Person will be discarded and all related Pet objects will have no relationships, so it will be nil. This is not possible if the Pet's relationship is non-optional.

Unlike using DBMS directly, Coredata manages the database itself, so the timing of merging can be so unclear and this can lead to some unexpected problems. Especially, when using iCloud sync, merging is frequently done automatically and users can't handle it almostly.

That's my opinion on why Apple prevent uniqueness constraints with one-to-one mandatory inverse relationship.

Ingles answered 31/5 at 8:17 Comment(0)
H
-2

If you are trying to add constraints with existing entity with records , The solution is 1. delete all records from existing entity 2. delete existing relationships with the entity . 3. Regenerate the +CoreDataClass and +CoreDataProperties agin.

Heal answered 29/3, 2019 at 12:9 Comment(1)
This is, for me at least, a compile time error, so doubt there be data is the issue. In fact deleting the app so there is no data still produces the issue.Algin
H
-4

Make your relationship properties "optional". That fixed this problem in my case.

Hubblebubble answered 11/11, 2015 at 18:1 Comment(1)
The question is explicitly about mandatory relationship. I know it works with optional, but lacks validation then.Kyser

© 2022 - 2024 — McMap. All rights reserved.