Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Core data bug refers to nonexistent core data attribute of reflexive many-to-many relationship

I am experiencing a perplexing Core Data bug, in which I receive the following error message when trying to save some data:

CoreData: error: (1) I/O error for database at /var/mobile/Applications/5D3C0F3C-E097-43BF-887B-2870B1148226/Documents/Database.sqlite.  SQLite error code:1, 'table Z_1RELATEDCARDS has no column named FOK_REFLEXIVE'

Core Data: annotation: -executeRequest: encountered exception = I/O error for database at /var/mobile/Applications/5D3C0F3C-E097-43BF-887B-2870B1148226/Documents/Database.sqlite.  SQLite error code:1, 'table Z_1RELATEDCARDS has no column named FOK_REFLEXIVE' with userInfo = {

    NSFilePath = "/var/mobile/Applications/5D3C0F3C-E097-43BF-887B-2870B1148226/Documents/Database.sqlite";

    NSSQLiteErrorDomain = 1;

}

For some context: there is no column "reflexive" in my data model. I have an entity, Cards, which has an attribute, relatedCards, that is a many-to-many relationship between Card items. I am quite confused as to what this error is referring to, and any assistance would be greatly appreciated.


UPDATE

As per a great suggestion in the comments, I ran the app in the iOS Simulator with the argument -com.apple.CoreData.SQLDebug 3 and received the following response:

CoreData: annotation: Connecting to sqlite database file at "/Users/jason/Library/Application Support/iPhone Simulator/5.0/Applications/4EE6D378-A946-4EBF-9849-F7D2E58F2776/Documents/Database.sqlite"
CoreData: sql: pragma cache_size=200
CoreData: sql: BEGIN EXCLUSIVE
CoreData: sql: UPDATE ZCARD SET ZDATEMODIFIED = ?, Z_OPT = ?  WHERE Z_PK = ? AND Z_OPT = ?
CoreData: details: SQLite bind[0] = "338478797.092588"
CoreData: details: SQLite bind[1] = (int64)7
CoreData: details: SQLite bind[2] = (int64)119
CoreData: details: SQLite bind[3] = (int64)6
CoreData: sql: UPDATE ZCARD SET ZDATEMODIFIED = ?, Z_OPT = ?  WHERE Z_PK = ? AND Z_OPT = ?
CoreData: details: SQLite bind[0] = "338478797.092577"
CoreData: details: SQLite bind[1] = (int64)7
CoreData: details: SQLite bind[2] = (int64)100
CoreData: details: SQLite bind[3] = (int64)6
CoreData: sql: INSERT OR REPLACE INTO Z_1RELATEDCARDS(Z_1RELATEDCARDS, REFLEXIVE, FOK_REFLEXIVE) VALUES (119, 100, 0)
CoreData: annotation: Disconnecting from sqlite database due to an error.
CoreData: error: (1) I/O error for database at /Users/jason/Library/Application Support/iPhone Simulator/5.0/Applications/4EE6D378-A946-4EBF-9849-F7D2E58F2776/Documents/Database.sqlite.  SQLite error code:1, 'table Z_1RELATEDCARDS has no column named FOK_REFLEXIVE'
[Switching to process 45402 thread 0x15503]

For a little context, I have modified the Card table to keep track of when it is modified. That's what's going on in the upper portion of the debug output. However, the key line in the debug output is clearly the fourth from the bottom:

CoreData: sql: INSERT OR REPLACE INTO Z_1RELATEDCARDS(Z_1RELATEDCARDS, REFLEXIVE, FOK_REFLEXIVE) VALUES (119, 100, 0)

I went into my SQLite database and checked, there is no column FOK_REFLEXIVE in this table. The schema for this table is:

CREATE TABLE Z_1RELATEDCARDS ( Z_1RELATEDCARDS INTEGER, REFLEXIVE INTEGER, PRIMARY KEY (Z_1RELATEDCARDS, REFLEXIVE) );

So clearly, Core Data is trying to insert data into a field which does not exist. What am I supposed to do with this?

Update:

This is also an issue reported by users. I can't update my app and just tell users "oh well you need to trash your data store and start over." That won't go over very well unfortunately even if it were the cause of this error.

like image 613
Jason Avatar asked Sep 22 '11 13:09

Jason


People also ask

What kind of database is core data?

Core Data is not a database. Core Data is a framework for managing an object graph. An object graph is nothing more than a collection of interconnected objects. The framework excels at managing complex object graphs.

Where does core data store data?

The persistent store should be located in the AppData > Library > Application Support directory.

Could not merge changes Core Data?

Problem: You see the error message, " Could not merge changes ." Cause: Two different managed object contexts tried to change the same data. This is also known as an optimistic locking failure. Remedy: Either set a merge policy on the context, or manually (programmatically) resolve the failure.


2 Answers

[Update: Based on the authors comments to this answer, this is not the cause. The issue affects end uses and he does not modify the sqlite file. I'll leave this answer here just for future reference. --TechZen]

The reflex here is probably a reflexive join in SQL (also called a self join.) The REFLEXIVE in the SQLDebug output is probably the command to create a join table or similar construct. In this case, your Card entity probably has a relationship to itself Core Data uses a reflexive sql relationship to persist that entity relationship.

You say that:

I have modified the Card table to keep track of when it is modified…

… from which I take it that you have modified the sqlite store file directly. That usually causes problems, including corruption. Core Data uses a proprietary sql schema which is undocumented. Any changes to it or even the sqllite runtime can cause problems.

I think the most likely issue is that the store file is corrupt. You very seldom get SQL errors from Core Data objective-c code and when you do, its almost always related to a predicate that SQL can't run.

Start over with a clean version of your database without any tinkering and see if it works.

like image 111
TechZen Avatar answered Nov 15 '22 11:11

TechZen


I had just run into this issue as well. It is an issue for you and your customers. Much more so if your app is on the market.

There appears to be an issue with the way core data aliases several many-to-many relationships contained in one entity. Look AT THIS POST and THIS ONE AS WELL.

The reported solution in the first hyperlink did not solve my issue. To mitigate, I made a container entity to allow for my many-to-many to look like many-to-one-to-many. But, if our app is already on the market, you would need to migrate to keep user data.

It seems like you are getting your exception at the start. If this isn't the case, consider in-memory filtering if you're failing on a predicate, and you are not getting the exception on your root most entity.

It also appears that this is only an issue sometimes. I have several entities containing multiple many-to-many relationships. There was only one entity that had this issue. The problem entity had two many-to-many relationships, and one to-one relationship; all of which were optional. The to-one delete rule was cascade, both to-many's: nullify.

Another entity that does not cause this issue has relationships:

  • 1 one-to-many relationship, optional, cascade
  • 2 to-one relationships, optional, cascade
  • 3 many-to-many relationships, optional, nullify

What's the difference??? I'm not sure. I'm tempted to create entity containers for these many-to-many's as well to avoid your issue.

like image 31
stephen Avatar answered Nov 15 '22 11:11

stephen