bugGNUstep - Bugs: bug #18938, Wrong nullify in ToMany...

 
 

You are not allowed to post comments on this tracker with your current authentication level.

bug #18938: Wrong nullify in ToMany relationship

Submitted by:  Manuel Guesdon <mguesdon>
Submitted on:  Fri 02 Feb 2007 06:36:55 PM UTC  
 
Category: gdl2Severity: 3 - Normal
Item Group: BugStatus: Fixed
Privacy: PublicAssigned to: David Ayers <ayers>
Open/Closed: Closed

Sun 11 Feb 2007 08:56:43 AM UTC, comment #3:

Hi Manuel, I've spent some time this week debugging this issue and thinking about how to resolve it best. I haven't come to a conclusion yet though, so I think the 2 pass approach is fine for a stop-gap for now.

For documentation sakes, the problem stems from the fact that we process the changed objects in arbitraty order (which in itself is fine), yet the this one change actually causes changes in 3 different objects. One to update the toOne and two to update the toMany relationships of the affected entities. Now depending on which of the two toMany relationships gets processed last, the attribute is either set to null or the new value.

I've got two concerns...
1) This part is where some the most complex processing of GDL2 happens so two passes seems painfull performance wise but I haven't done any measurements.
2) I'm still trying to think of complex situatation where we may have more conflicting changes that overwrite each other.

It may be a non-issue as I've been unsuccessfull in trying to conceive test cases where mutliple changes / 'legal' reltionships would be consolidated into more than these 3 changes. I would feel more comfortable with an approach that takes the sequence of the changes into account, but this seems extremly intrusive.

So for now, let's try the two pass approach until we come up with something better. I hope to find the time to document the involved methods better and maybe come up with an approach that allows us to handle this in one pass.

And just for the record, this issue indeed is applicable independent of whether the foreign key is a class property or whether a removeObject:fromBothSidesOfRelationshipWithKey: is explicitly set. It just happend that adding the calls sometimes changed the order in which the hash enumerator processed the changes and therefor papered over the issue.

Also please note that the exception with respect to class properties is for the case of the primary key attribute. A primary key is immutable and you can expect the relationships and class properties to be in sync once the object has been inserted. But foreign keys of mutable relationships can change. Note that if you change the relationship, that the foreign key class attribute is not updated by GDL2 (nor EOF) until the object is refaulted / invalidated and refetched.

David Ayers <ayers>
Project MemberIn charge of this item.
Tue 06 Feb 2007 12:01:56 PM UTC, comment #2:

About the addObject:toBothSide...
There's a [object removeObject:oldObject fromPropertyWithKey:inverseKey];
(but may be you're talking about another place).

You're right about the reference but anyway, smetimes on have to add it as propertiy: "The only exception to this rule is when the key has meaning to the user (such as a credit card number) and therefore must be displayed in the user interface."

So I'm inclined to think that the safest way is doing the update in 2 pass: first nullify, next relay. It seems not too hard to store relayAttributesInRelationship call arguments and do them after the update/nullify pass.
I can try this if you agree.

Manuel

Manuel Guesdon <mguesdon>
Project Member
Mon 05 Feb 2007 10:17:41 PM UTC, comment #1:

IIUC, the behavior due to the entity definition may partly undefined as primary and foreign keys should not be class properties.

http://developer.apple.com/documentation/LegacyTechnologies/WebObjects/WebObjects_4.5/System/Documentation/Developer/EnterpriseObjects/DevGuide/EOsI2.html#821
Eventhough they name exceptions to this rule, it's my experience that these exceptions cause issues as you are refering to. I think GDL2 could try to support primary keys as class attributes, but I don't think the hastle for foreign keys is managable and a lot less useful. (Primary keys being generally immuatable cause a lot less house keeping).

Yet when trying to create a test case, I noticed some issues with propagating the foreign key with addObject:toBothSidesOfRelationshipWithKey: without calling removeObject:fromBothSidesOfRelationshipWithKey: to clear the previous relationship, which when fixed, may happen to resolve your issue also. I just need to find some time to look at it a bit.

David Ayers <ayers>
Project MemberIn charge of this item.
Fri 02 Feb 2007 06:36:55 PM UTC, original submission:

Having 2 entities like this:
{
attributes = (
{
columnName = code;
externalType = int4;
name = code;
valueClassName = NSNumber;
valueType = i;
allowsNull = N;
},
);
attributesUsedForLocking = (code);
classProperties = (code,toEntity2);
externalName = entity1;
primaryKeyAttributes = (code);
name = Entity1;
className=Entity1;
relationships = (
{
destination = Product;
joinSemantic = EOInnerJoin;
isToMany = Y;
isMandatory = N;
isBidirectional = Y;
joins = (
{
destinationAttribute = foreignCode;
joinOperator = EOJoinEqualTo;
joinSemantic = EOInnerJoin;
sourceAttribute = code;
}
);
name = toEntity2;
}
);
}

{
attributes = (
{
columnName = code;
externalType = int4;
name = code;
valueClassName = NSNumber;
valueType = i;
allowsNull = N;
},
{
columnName = foreign_code;
externalType = int4;
name = foreignCode;
valueClassName = NSNumber;
valueType = i;
allowsNull = Y;
userDictionary = { isUserNotNull = YES; min=1; max=INT_MAX; };
}
);
attributesUsedForLocking = (code);
classProperties = (code,foreignCode,toEntity1);
externalName = entity2;
name = Entity2;
className=Entity2;
primaryKeyAttributes = (code);
relationships = (
{
destination = Entity1;
joinSemantic = EOInnerJoin;
isToMany = N;
isMandatory = N;
isBidirectional = Y;
joins = (
{
destinationAttribute = code;
joinOperator = EOJoinEqualTo;
joinSemantic = EOInnerJoin;
sourceAttribute = foreignCode;
}
);
name = toEntity1;
}
);
}

For an existing Entity2 object having a toEntity1 relationship to ObjectA, changing this relationship to ObjectB sometimes save NULL in foreignCode instead of ObjectB code.
This append when update are propagated first with objectB as sourceObject (it assign the objectB value to foreignCode) and next with objectA (which nullify foreignCode).
If propagation first take objectA and next objectB, there's no problem.

The nullify operation is done in In EODatabaseContext -nullifyAttributesInRelationship:sourceObject:destinationObject:

Any idea on this ? Should we firs apply all nullify operations and next all relay operations ?

Manuel

Manuel Guesdon <mguesdon>
Project Member

 

No files currently attached

 

Depends on the following items: None found

Items that depend on this one: None found

 

Carbon-Copy List
  • -unavailable- added by ayers (Posted a comment)
  • -unavailable- added by mguesdon (Submitted the item)
  •  

    Do you think this task is very important?
    If so, you can click here to add your encouragement to it.
    This task has 0 encouragements so far.

    Only logged-in users can vote.

     

    Please enter the title of George Orwell's famous dystopian book (it's a date):

     

     

    Follow 6 latest changes.

    Date Changed By Updated Field Previous Value => Replaced By
    Sun 06 May 2007 11:46:06 AM UTCayersStatusNone=>Fixed
      Open/ClosedOpen=>Closed
    Mon 05 Feb 2007 10:17:41 PM UTCayersSeverity4 - Important=>3 - Normal
      Assigned toNone=>ayers
    Fri 02 Feb 2007 06:36:55 PM UTCmguesdonCarbon-Copy-=>Added ayers
      Carbon-Copy-=>Added ratmice

    Back to the top


    Powered by Savane 3.1-cleanup1