First thing to check is your data. Is the "uid" column has a non null or primary key constraint ?
Absolutely, it is the very PK; modelled as (the only) non-null integer key:
=== DBRecord.plist ===
...
{
className = NSNumber;
columnName = "C_UID";
externalType = INTEGER;
name = uid;
valueType = i;
},
...
attributesUsedForLocking = (
uid
);
...
primaryKeyAttributes = (
uid
);
...
=== Database ===
CREATE TABLE "T_RECORD" (
...
"C_UID" INTEGER NOT NULL,
...
);
SET UNIQUE = 1000000 FOR "T_RECORD";
ALTER TABLE "T_RECORD" ADD PRIMARY KEY ("C_UID") NOT DEFERRABLE INITIALLY IMMEDIATE;
===
Besides, it usually fetches all right, only occasionally fails — far as I can say, only when the background task happens to fetch at the same time. It is pretty difficult to catch the fail; I'm playing for hours and hours with the thing now, and so far I've succeeded to see ten-odd fails only (and I've tried to repeat the background threads unnecessarily, increase their number, etc., to increase the probability — so far in vain).
I've also meantime tried to
- lock the background thread ECs
- lock the background thread OSCs
- replace the return ERXEOControlUtilities.objectCountWithQualifier(this.editingContext, 'DBRecord', mymasterrow) code by
===
EOFetchSpecification fs=new EOFetchSpecification('DBRecord', mymasterrow, nil)
fs.fetchesRawRows=YES
fs.rawRowKeyPaths=new NSArray('uid')
return this.editingContext.objectsWithFetchSpecification(fs).count()
===
Nothing helped. On the other hand, when I've
- switched off the background threads completely
- or, reduced ERXObjectStoreCoordinatorPool.maxCoordinators to 1 (which of course considerably slowed the app, for now the worker threads had to wait for the background tasks, using all the same DB channel)...
... the problem never occurred; either it really fixed it, or I was just not lucky enough to see it (see the low probability above).
Real weird.
If there is a constraint, can you indicate the database column type and model type used ?
Not sure what is a model type? Normal model, the .eomodeld folder containing all those plists; I've never seen any other. As for the rest, see please above.
Thanks and all the best,
OC
Hi there,
just bumped into another weird EOF case. A pretty plain fetch caused a “Cannot determine primary key for entity” exception. The row contains a number of columns whose values makes sense, some null, some non-null, with one exception — the primary key, modelled as an attribute uid, is indeed a null, thus the exception makes a perfect sense.
How can this happen?
===
IllegalArgumentException: Cannot determine primary key for entity DBRecord from row: {... uid = <com.webobjects.foundation.NSKeyValueCoding$Null>; ... }
at com.webobjects.eoaccess.EODatabaseChannel._fetchObject(EODatabaseChannel.java:348)
... skipped 2 stack elements
at com.webobjects.eocontrol.EOObjectStoreCoordinator.objectsWithFetchSpecification(EOObjectStoreCoordinator.java:488)
at com.webobjects.eocontrol.EOEditingContext.objectsWithFetchSpecification(EOEditingContext.java:4069)
at er.extensions.eof.ERXEC.objectsWithFetchSpecification(ERXEC.java:1215)
... skipped 1 stack elements
at com.webobjects.eocontrol.EOObjectStoreCoordinator.objectsForSourceGlobalID(EOObjectStoreCoordinator.java:634)
at com.webobjects.eocontrol.EOEditingContext.objectsForSourceGlobalID(EOEditingContext.java:3923)
at er.extensions.eof.ERXEC.objectsForSourceGlobalID(ERXEC.java:1178)
... skipped 1 stack elements
at com.webobjects.eoaccess.EOAccessArrayFaultHandler.completeInitializationOfObject(EOAccessArrayFaultHandler.java:77)
at com.webobjects.eocontrol._EOCheapCopyMutableArray.willRead(_EOCheapCopyMutableArray.java:45)
at com.webobjects.eocontrol._EOCheapCopyMutableArray.count(_EOCheapCopyMutableArray.java:103)
at com.webobjects.foundation.NSArray.isEmpty(NSArray.java:1888)
...
===
Just in case it happens to be important (I believe it is not), the problem happens at row
... =eolist.representedObject.records().isEmpty()?...:...
where records just returns storedValueForKey('records'), self-evidently a fault, which fires to fetch the rows.
Searching the Web, all I've found is
this (linked from
here), which does not really help :) Truth is, some background threads
do run at the moment; they are comparatively plain though and I can't see why they should cause the problem for the R/R thread. All they do is to
1. get their own OSC from the pool, making sure they never get the same OSC normal sessions have
2. create a new ERXEC in this OSC
3. get a local instance of an object in the EC
=== this is the code of the background thread; a number of those runs:
def store
for (def pool=ERXObjectStoreCoordinatorPool._pool();;) {
store=pool.nextObjectStore
if (store!=_sessionosc) break // there's one OSC for all sessions, stored in _sessionosc
}
return eo.localInstanceIn(ERXEC.newEditingContext(store)).numberOfMasterRowsWithoutOwner()
===
and the method simply fetches:
===
int numberOfMasterRowsWithoutOwner {
def mymasterrow=EOQualifier.qualifierWithQualifierFormat("importObject.dataBlock = %@ AND recordOwner = NULL",[this] as NSA)
return ERXEOControlUtilities.objectCountWithQualifier(this.editingContext, 'DBRecord', mymasterrow)
}
===
Most time it works properly. Occasionally — rather rarely — the problem above happens. Can you see what am I doing wrong?
Thanks a lot,
OC