Re: Multithreading EOAccess

Jonathan Rochkind <[email protected]>
Newsgroups gmane.comp.web.webobjects.eof
Message-ID <[email protected]>
Everyone who has responded generally tells me to give up on changing the 
EOModel. However, for the situation I am in, I don't think I need to worry 
about changing the model after some things have been fetched.  But the 
inability to take out the appropriate locks easily may be a problem. Let me 
explain the situation, becuase it would be really convenient if I could do 
this.

Sometimes you want, instead of fetching actual EOs or even raw rows, simply 
to fetch a count(*) associated with an entity and qualifier. To answer the 
question, how many EOs are there that match this qualifier?  If you don't 
actually need the EOs or raw rows, it is much faster to simply execute an 
SQL count(*).  So the question becomes: how do we execute this count?

One way, is you can add an EOAttribute to the EOModel. First, I tried 
actually adding it to the .eomodeld file at compile time. You add a derived 
attribute defined as "count(*)". Let's say we call it "objectCount". This 
attribute is NOT a class property, nor is it used for locking. So normally, 
it's as if it wasn't there at all. However, when you want to execute a 
count(*) query, you set up a fetch spec with the qualifier you want, and 
then call:
         setRawRowKeyPaths( new NSArray( "objectCount" ) )
on the fetch spec.

This works great. You get back an array that contains one object, a 
dictionary that contains one key/value, and that value is the count.

So far so good, and we didn't need to modify the EOModel at run time. But 
then I considered, wouldn't it be nice if we didn't have to define 
objectCount attributes in every single EOEntity we might want a count() 
for. Then they wouldn't be there mucking up the .eomodeld, and it would 
just plain be niftier if we could just call a utility method, give it an 
EC, an EOEntity, and an EOQualifier, and get back a count, without needing 
to define the special count attribute in the .eomodeled.

To do this, I had my utility method add the special attribute at run-time, 
if it has not yet been added. Since the attribute is not used for locking 
OR as a class property, I don't see any way it would cause a problem---even 
if objects have already been fetched from that entity. The new attribute we 
are adding should never be included in a snapshot, after all.

I wrote code that does this, it seems to work---I have yet to have a 
problem with it. It works. However, I realized that there are potentially 
problems with concurrency, with editing the EOModel at run time.

If I just plain can't edit the EOModel at run time, so be it. I can add the 
attribute to all the neccesary EOEntities at compile time.

However, I got this idea from some other code:  That I got from Gary Teter 
(originally by David Koski in Obj C), to add duplicate relationships, to 
allow aliasing the same destination table twice in a query. You need to do 
this sometimes to generate the proper SQL for some querries on to-many 
relationships. If you want to get all objects that have A in their to-many 
relationship OR B in their to-many relationship, you've got to alias the 
destination table twice in the SQL. This code accomplishes that by 
duplicating the relationship (as a non-class property) in the EOModel, 
on-demand, at run-time, with a method called touchRelationship.  I believe 
this code is used in some of the Project Wonder stuff too. I don't think 
there's any other way to generate this kind of perfectly reasonable SQL, 
but here it's harder to avoid modfying the EOModel at run time. Depending 
how many "OR" clauses you have, you might need that many extra 'duplicate' 
relationships.  The number you need isn't neccesarily fixed at compile time.

This code, that I got from others on the list, also doens't seem to be 
taking out any locks before modifying the EOModel, and even though it seems 
to work, seems dangerous in the same way.

So if there's no way to safely modify an EOModel at runtime... we're kind 
of out of luck.

At 02:24 PM 11/19/2002 -0800, you wrote:
>Jon,
>
>Before 5.2, there was a global EOAccess lock.  If you locked any 
>EODatabaseContext, you locked all of EOAccess (more or less).
>
>As for the new locking methods, those classes now implement 
>NSLocking.  None of them have anything to do with EOModels. EOObjectStore 
>is the abstract super class of various other classes, like EOEditingContext.
>
>EOEditingContext's new method lockObjectStore() secures the lock for the 
>parent EOObjectStore of that EC.  For normal ECs, this will be the 
>EOObjectStoreCoordinator.
>
>The best way to lock an "EOF stack" is to grab the 
>EOObjectStoreCoordinator's lock.  To lock all database operations, you'd 
>have to keep track of all the OSCs and lock them all.
>
>Since the model objects (like EOEntities) cache some information, you will 
>probably experience difficulties changing the model after a fetch has 
>occurred.  We haven't gotten to conflicts with snapshots, or EO class 
>properties.
>
>You're probably better off configuring things before any EOF operations 
>take place, or creating a new EOModelGroup.
>--
>
>-Ben
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.