Re: Dangling reference across non-ClassProperty relation
Re: Dangling reference across non-ClassProperty relation
- Subject: Re: Dangling reference across non-ClassProperty relation
- From: Chuck Hill <email@hidden>
- Date: Fri, 5 Nov 2010 09:58:59 -0700
On Nov 5, 2010, at 8:06 AM, Kasper Frederiksen wrote:
> Hi Chuck,
>
> On Thu, Nov 4, 2010 at 5:45 PM, Chuck Hill <email@hidden> wrote:
>>
>> Hi Kaspar,
>>
>> On Nov 4, 2010, at 5:08 AM, Kasper Frederiksen wrote:
>>
>>> I have a referential integrity problem in my model and I am at a loss as to how to debug this.
>>>
>>> To illustrate the problem in it's simplest form, I have made a model containing two entities: User and Ticket. User has a ticket foreign key (ticketFK) entity and a to-one relationship that maps User.ticketFK to a Tiket primary key (ticketID).
>>
>> Can you switch this? Have Ticket.userFK as the relationship join? That would result in a user.tickets() relationship in EOF.
>>
> You posed an interesting question here, so I spent some time exploring
> this option:
>
> I removed the to-one relationship user.ticket() from User.ticektFK to
> Ticket.ticketID and added the relationship user.tickets() from
> User.userID to Ticket.userFK. This meant that I needed to add the
> attribute Ticket.userFK. To fill out this new attribute I removed the
> old ticket.user() relation (Ticket.ticketID --> User.ticketFK) and
> replaced it with: Ticket.userFK --> User.iserID.
>
> Now there is no longer a need to have User.ticketFK, so I deleted this
> attribute along with the row in the database table.
>
> Now running the test again, of course the database ends up in a
> consistent state since the troublesome column User.ticketFK no longer
> exists.
>
> The reference from Ticket to User is no longer public (it is not a
> class property). But it is not a complete success, because of the
> following:
> 1) fetch a User in to editing context A.
> 2) add to this user three tickets in editing context A.
> 3) localize one of the tickets in to editing context B, delete it
> and save editing context B.
> 4) back in editing context A, read the relation User.tickets and
> print out the contents of the array.
> ... it turns out that the user in editing context A still has three
> tickets in step 4.
>
> Remember, this was all done with the relation
> Ticket.userFK-->User.userID NOT being a class property. If I change
> this relation to a class property (writing Ticket.setUser() and
> Ticket.getUser() along the way), THEN step 4 will report that the user
> has two tickets ...and we are back where we started :)
>
>>
>>> Tickets may become invalid, then this happens they are deleted. This will typically happen in a separate editing context from the one containing the User. To avoid users referencing a Ticket that does not exist I make a relation from Ticket.ticketID to User.ticketFK and set the delete rule to 'nullify'.
>>>
>>> There is no need for the business code to reference the user through the ticket, so I do not mark the relation from Ticket to User as a class property.
>>>
>>> To test, I fetch a User and follow the relation to get the User's Ticket. Then I localize this Ticket in to a new editing context, delete the local Ticket and save the new editing context. I the database the ticket row is gone. The User object still refers to the ticket -this can't be helped, it is seeing cache. The problem is this: the User row in the database still has ticketFK set! It is pointing to a Ticket row that does not exist. Saving the Users editing context or termination the application does not change this.
>>
>> Using the modeling above will still leave you with the User referring to the deleted ticket unless you have a delete rule from Ticket to User. However this won't be in the database and won't "stick".
>
> I am not sure I see your point. I agree that a delete rule ('nullify')
> from Ticket to User is necessary. It seems that the change does
> "stick", but only if the reference from Ticket to User is a class
> property (eg. public).
I meant that if you restart the app or use Wonder to refresh the User.tickets() relationship, that you will see the correct results. But the object graph will be in an inconsistent state unless you do that (or have the backwards relationship a class property).
>>> Does some one have any suggestions as to how I debug why the 'nullify' rule on the Ticket-->User relation does not work?
>>>
>>> Here are some of my further observations on the problem:
>>> ---
>>> No User update SQL is sent to the database, only the delete for the Ticket row.
>>>
>>> I have tried changing the Ticket-->User relation to a class property. Since the destination is not a primary key, WO now insists the relation be modeled as to-many. I also write the getter and setter for the Users on the Ticket. Now the above example works perfectly! The price I had to pay, is an additional getter and setter in the business API. I would very much like to avoid this since no business rule will ever need them and it is just cluttering up the API.
>>
>> I think you can remove the methods, EOF will use KVC to get around not having them.
>
> I was using EOCustomObject out of habit (they perform better than
> EOGenericRecord), but this is an interesting suggestion. Switching to
> EOGenericRecord allows me to simplify my example even further. In my
> new test I never wrote a Java implementation for User and Ticket, I
> simply told the model they where EOGenericRecords and set the
> relations using KVC before I saved. Unfortunately I was still able to
> recreate all the effects described so far. The relation from Ticket to
> User must be a class property for the delete rule to trigger.
Yes, it must be a class property. I just meant that you could probably delete the Java methods generated for this relationship if you wanted to clean up the Java API.
>>> I am beginning to suspect that the model defined delete rules are only triggered for relations that are also class properties. Can any one confirm this?
>>
>> I think this is the case now. I think it was not the case in earlier versions, but I am not sure.
>
> That sounds plausible, one of my older colleagues seems to recall that
> this worked "back in the day" :)
> We are currently running version 5.3.3.
> What version are you using?
5.4.3
> Can you remember when this change might have happened?
Probably 5.1 or 5.2. I see it more as a new bug than a "feature" change.
> After this latest round of tests, I am ready to conclude that EOF
> references need to be public to trigger the delete rule and will
> instead work on a clever way to shield this reference from misuse by
> the API programmer. If some one else has a break through, please let
> me know.
Just delete the Java methods: out of sight, out of mind.
Chuck
--
Chuck Hill Senior Consultant / VP Development
Practical WebObjects - for developers who want to increase their overall knowledge of WebObjects or who are trying to solve specific problems.
http://www.global-village.net/products/practical_webobjects
Attachment:
smime.p7s
Description: S/MIME cryptographic signature
_______________________________________________
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