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