Re: Why doesn't EOF sort our PK problems itself ?
Re: Why doesn't EOF sort our PK problems itself ?
- Subject: Re: Why doesn't EOF sort our PK problems itself ?
- From: David Elliott <email@hidden>
- Date: Wed, 23 Jan 2008 22:38:11 -0500
Hi Chuck,
On Jan 23, 2008, at 4:19 PM, Chuck Hill wrote:
On Jan 23, 2008, at 12:06 PM, David Elliott wrote:
[...]
You're correct in thinking such a fix would be a DB-specific
thing. One advantage though is that at least as far as I know, PK
constraints are rarely deferred as there is no reason I know of to
do so. At least with Posstgres, PK constraints cannot be deferred
as far as I know. It completely defeats the point of a primary key.
I defer the ones on join tables. EOF can update these out of sync
when relationships between two objects are removed and restored.
So it can do the insert before the delete. Of course, EOF could be
fixed to do the ordering properly...
I seem to remember fixing this myself at one time but not by
modifying the database to avoid checking PKs. In fact, such a thing
is somewhat dangerous because it leaves no way to distinguish two
records. For example, suppose you have a join between foo and bar
named foo_bar whose PK is (foo_id, bar_id). You want the DB to fail
to insert a record with the same PK because deleting the record will
certainly not fail, it will instead delete both the one you just
inserted and the one that existed. Clearly you want to update the
record because we're not talking about two records here we're talking
about one record. The two records you are thinking of are the same
record.
And therein lies the true solution to the problem. The mistake that
you make (and that over 99% of EOF users make) is to think of it as
two records. This cannot be true because by definition two records
with the same primary key are the same record. It hasn't really been
deleted then inserted, only other attributes have changed on it.
Once you realize this truism it becomes much more clear where the bug
really lies.
The problem is that up in the EOControl layer you have committed the
most horrible sin against EOF. Namely, you have two Global IDs for
what amounts to the same object. To clarify things I am only talking
here about the case when the join table actually exists as an
object. If you use the standard many-to-many join where there are no
additional attributes in the join table and your to-many
relationships are flattened through it then you do not have this
problem because the join record does not exist in EOControl and
EOAccess will take care of doing nothing at all rather than trying to
delete and insert the same join record.
So the fix here is that just before saving changes to the parent
object store (whether this is another editing context or the actual
object store does not matter) you need to check for all entities with
compound PKs if their two-one relationships are all pointing to
objects with non-temporary global IDs. If that is true then you know
there is the possibility that the join record existed in the object
store. You can easily ask your editing context which objects have
been deleted. So what you do is you compound the global ID yourself
and look for that object. If you find it then you've got to modify
the object graph such that EOF knows that the object didn't get
deleted but rather that for the given global ID you've got this new
object that is an updated object.
It's slightly breaking the tenant that only one object exists per
global ID, but not really. You see, if the old object had been
deleted then the only reference to it was the EC's deletedObjects
list. Thus, when you remove the old one from that array and put the
new one in the updatedObjects list the old one is no longer
referenced by anything meaning that you haven't really violated the
rules, only very slightly bent them.
Unfortunately I can't remember all of the specifics and I don't have
the code (my previous employer has that) so I can't show you that
either. But I can tell you it's possible and that it's the by far
the cleanest solution to this problem because it solves the problem
by not creating the problem in the first place.
[...]
Nothing's _impossible_ :), but I suspect it is pretty tricky to
get it to work right. You basically have all the same context
the framework does at this point, though. I suspect you could
try to prototype this in your own code at a higher level to see
if there's even enough info available to pull it off.
I assure you there's enough information to pull it off, but it
would have to be done very deep in the EOAccess layer, probably
via a delegate, and doing it requires a very deep understanding of
EOF and a very deep understanding of why EOF works the way it
does. Every problem with PKs in EOF translates to a lack of
understanding on the part of the developer as to how EOF does its
thing. The best reference on this stuff is Chuck and Sacha's book
with the bumble-bee cover but even that does not (believe it or
not) go deep enough.
Mmmm. Mike is the person that _I_ ask when I have a question on
the deep down EOF internals. I'm pretty sure he "gets" it.
Sorry, I didn't mean to disparage Mike's knowledge of EOF only point
out that not one of us can claim to have a complete understanding of
the framework. When one person says it cannot be done another person
can say it can be done and here's how.
We also all have different ideas about how best to handle the
problems we encounter with EOF. My experience has been that the best
path is the one of least resistance. Fighting the framework trying
to reinvent the EOAccess layer and its relationship to the database
is in my opinion the wrong way to go about things.
-Dave
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Webobjects-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden