Thread: [Modeling-users] toOne relationship returns base class instead of subclass?
Status: Abandoned
Brought to you by:
sbigaret
From: John L. <jl...@gm...> - 2004-07-22 17:15:57
|
in the model Person / \ | PhysicalPerson <---->> Address querying an Address for its PhysicalPerson returns Person instances, which was unexpected (for me, at least). Is this correct, or is it a bug? -- John Lenton (jl...@gm...) -- Random fortune: bash: fortune: command not found |
From: Sebastien B. <sbi...@us...> - 2004-07-23 13:03:18
|
John Lenton <jl...@gm...> wrote: > in the model >=20 > Person > / \ > | > PhysicalPerson <---->> Address >=20 > querying an Address for its PhysicalPerson returns Person instances, > which was unexpected (for me, at least). Is this correct, or is it a > bug? If you mean that, having an address 'addr', addr.getPerson() has class 'Person', yes, this is intended, as long as addr.getPerson().isFault() is True. As soon as you'll need an addr's person property the fault will be fired and you'll get the correct class for addr.getPerson(). Now you may wonder why this is like this. We discussed this here: https://sourceforge.net/mailarchive/forum.php?thread_id=3D3457563&forum_id= =3D10674 See esp. the third post dated 2003-11-15 20:40. While the example taken there involves a relationship pointing from a subclass to its root class, you'll see that you get exactly the same kind of problem if you add a class Photo such as: Photo <<---> Person Now you'll see that the discussion "ended" there with an open question, about if and how this could/should be changed. Time to rediscuss this I guess, huh? -- S=E9bastien. PS: BTW the interesting methods on this topic:=20 DBChannel.fetchObject() calling DBContext.initializeObject(), which in particular populates the object's toOne properties with DBContext.faultForGlobalID(). and this particular behaviour is tested in:=20 test_EC_Global_Inheritance.test_02_toOneFault() |
From: John L. <jl...@gm...> - 2004-07-23 16:48:22
|
On 23 Jul 2004 15:02:00 +0200, Sebastien Bigaret <sbi...@us...> wrote: > > > Now you'll see that the discussion "ended" there with an open > question, about if and how this could/should be changed. Time to > rediscuss this I guess, huh? ok, I've got no self-control, and I read the post. I then added the following __getattr__ to CustomObject---I'm not at all certain this is where it belongs, but it worked for me :) Not in production, and not tested, but I thought I'd post it anyway It does some magic with sys._getframe to ensure it's not called recursively; it does it after checking the attribute doesn't start with an underscore---which I'm not certain is ok. def __getattr__(self, attr): if attr.startswith('_'): raise AttributeError f = sys._getframe() if f.f_code is f.f_back.f_code: raise AttributeError print >> sys.stderr, "*** faulting object %s: %s called" % (self, attr) self.willRead() return getattr(self, attr) if this is the kind of thing we're talking about, I see no problem with it---the default behaviour is preserved due to the raising of AttributeErrors, and it's not *too* expensive. The _getframe magick isn't essential, but it helps. This still didn't fix the other issue, however... -- John Lenton (jl...@gm...) -- Random fortune: bash: fortune: command not found |
From: John L. <jl...@gm...> - 2004-07-23 13:46:17
|
On 23 Jul 2004 15:02:00 +0200, Sebastien Bigaret <sbi...@us...> wrote: > > John Lenton <jl...@gm...> wrote: > > in the model > > > > Person > > / \ > > | > > PhysicalPerson <---->> Address > > > > querying an Address for its PhysicalPerson returns Person instances, > > which was unexpected (for me, at least). Is this correct, or is it a > > bug? > > If you mean that, having an address 'addr', addr.getPerson() has class > 'Person', yes, this is intended, as long as addr.getPerson().isFault() > is True. As soon as you'll need an addr's person property the fault will > be fired and you'll get the correct class for addr.getPerson(). actually, what's biting me is this (I'm translating from a different model into this one that is similar to the example, for clarity and brevity; I hope I don't muss ep): >>> [i.getPerson().getId() for i in ec.fetch('Address')] [4, 5] >>> ec.fetch('Address', 'person.id == 4') [] in trying to simplify this last time I got the behaviour above, which I misinterpreted as the same thing. > Now you may wonder why this is like this. We discussed this here: > https://sourceforge.net/mailarchive/forum.php?thread_id=3457563&forum_id=10674 ok. Will read up---tomorrow (deadlines...!) -- John Lenton (jl...@gm...) -- Random fortune: bash: fortune: command not found |
From: Sebastien B. <sbi...@us...> - 2004-07-23 19:01:24
|
John Lenton <jl...@gm...> wrote: [...] > actually, what's biting me is this (I'm translating from a different > model into this one that is similar to the example, for clarity and > brevity; I hope I don't muss ep): >=20 > >>> [i.getPerson().getId() for i in ec.fetch('Address')] > [4, 5] > >>> ec.fetch('Address', 'person.id =3D=3D 4') > [] >=20 > in trying to simplify this last time I got the behaviour above, which > I misinterpreted as the same thing. Quickly replying here: this is absolutely not normal, and it would help a lot if you could provide a sample model, code and data (sal dump is ok). Or maybe you were trying something like this? -> >>> [i.getPerson().getId() for i in ec.fetch('Address')] [4, 5] >>> ec.fetch('Person', id =3D=3D 4') [] instead of: >>> ec.fetch('Person', id =3D=3D 4', isDeep=3D1) # fetch the whole inheritc= e tree [<PhysicalPerson instance at 0x...>] -- S=E9bastien. |
From: Sebastien B. <sbi...@us...> - 2004-07-29 08:30:36
|
Hi John, Again, could you be a little more explicit, or exhibit a short example? Sorry for getting back on this, but the only way I think this can happen is the one I already posted (see below); if it's not the case, this is a serious bug I definitely do not want to let escape. Thanks for your help! -- S=E9bastien. Sebastien Bigaret <sbi...@us...> writes: > John Lenton <jl...@gm...> wrote: > [...] > > actually, what's biting me is this (I'm translating from a different > > model into this one that is similar to the example, for clarity and > > brevity; I hope I don't muss ep): > >=20 > > >>> [i.getPerson().getId() for i in ec.fetch('Address')] > > [4, 5] > > >>> ec.fetch('Address', 'person.id =3D=3D 4') > > [] > >=20 > > in trying to simplify this last time I got the behaviour above, which > > I misinterpreted as the same thing. >=20 > Quickly replying here: this is absolutely not normal, and it would help > a lot if you could provide a sample model, code and data (sal dump is > ok). >=20 > Or maybe you were trying something like this? -> >=20 > >>> [i.getPerson().getId() for i in ec.fetch('Address')] > [4, 5] > >>> ec.fetch('Person', id =3D=3D 4') > [] >=20 > instead of: > >>> ec.fetch('Person', id =3D=3D 4', isDeep=3D1) # fetch the whole inheri= tce tree > [<PhysicalPerson instance at 0x...>] >=20 >=20 > -- S=E9bastien. |
From: John L. <jl...@gm...> - 2004-07-29 18:10:20
|
On 29 Jul 2004 10:30:02 +0200, Sebastien Bigaret <sbi...@us...> wrote: > > Hi John, > > Again, could you be a little more explicit, or exhibit a short > example? Sorry for getting back on this, but the only way I think this > can happen is the one I already posted (see below); if it's not the > case, this is a serious bug I definitely do not want to let escape. sorry for not getting back to you. I have yet to sit down and reproduce that with the "stock" modeling; I'll try to do it today. The only difference between what I posted and what I actually ran was the names of the entities; as I say, I'll try to get a full example to you today. -- John Lenton (jl...@gm...) -- Random fortune: bash: fortune: command not found |
From: John L. <jl...@gm...> - 2004-08-25 03:53:09
Attachments:
model.py
|
On 29 Jul 2004 10:30:02 +0200, Sebastien Bigaret <sbi...@us...> wrote: > > Again, could you be a little more explicit, or exhibit a short > example? Sorry for getting back on this, but the only way I think this > can happen is the one I already posted (see below); if it's not the > case, this is a serious bug I definitely do not want to let escape. sorry for the delay in answering, and the confusion when doing so. I feel terribly embarrassed :( HOWever, here goes. With the attached model (which is ugly, and breaks some of your naming conventions, but I just hacked out the attributes and renamed things from the model being used by a team I'm helping to get up to speed), using vainilla MDL 0.9-pre17.1 and NF 0.7: >>> from Modeling.EditingContext import EditingContext >>> import Store >>> ec=EditingContext() >>> ec.fetch('Address')[0] <Address.Address object at 0x4071c74c> >>> a = _ >>> p = ec.fetch('Person', isDeep=1)[0] <Employee.Employee object at 0x4072d88c> >>> p = _ >>> a.getPerson() <Employee.Employee object at 0x4072d88c> >>> a.getPerson().getId() 1 >>> a.isFault() False >>> p.getAddress() <Modeling.FaultHandler.AccessArrayFaultHandler instance at 0x40733a4c> >>> list(p.getAddress()) [<Address.Address object at 0x4071c74c>] >>> ec.fetch('Address', 'Person.id == 1') [] >>> ec.fetch('Address', 'Person.id == 1', isDeep=1) [] -- John Lenton (jl...@gm...) -- Random fortune: bash: fortune: command not found |
From: Sebastien B. <sbi...@us...> - 2004-08-26 19:46:21
|
John Lenton <jl...@gm...> wrote: > On 29 Jul 2004 10:30:02 +0200, Sebastien Bigaret > <sbi...@us...> wrote: > >=20 > > Again, could you be a little more explicit, or exhibit a short > > example? Sorry for getting back on this, but the only way I think this > > can happen is the one I already posted (see below); if it's not the > > case, this is a serious bug I definitely do not want to let escape. >=20 > sorry for the delay in answering, and the confusion when doing so. I > feel terribly embarrassed :( Please don't feel embarrassed, that was worth waiting for it. > HOWever, here goes. >=20 > With the attached model (which is ugly, and breaks some of your naming > conventions, but I just hacked out the attributes and renamed things > from the model being used by a team I'm helping to get up to speed), > using vainilla MDL 0.9-pre17.1 and NF 0.7: >=20 >=20 > >>> from Modeling.EditingContext import EditingContext > >>> import Store > >>> ec=3DEditingContext() > >>> ec.fetch('Address')[0] > <Address.Address object at 0x4071c74c> > >>> a =3D _ > >>> p =3D ec.fetch('Person', isDeep=3D1)[0] > <Employee.Employee object at 0x4072d88c> > >>> p =3D _ > >>> a.getPerson() > <Employee.Employee object at 0x4072d88c> > >>> a.getPerson().getId() > 1 > >>> a.isFault() > False > >>> p.getAddress() > <Modeling.FaultHandler.AccessArrayFaultHandler instance at 0x40733a4c> > >>> list(p.getAddress()) > [<Address.Address object at 0x4071c74c>] > >>> ec.fetch('Address', 'Person.id =3D=3D 1') > [] > >>> ec.fetch('Address', 'Person.id =3D=3D 1', isDeep=3D1) > [] Wooo, I didn't even realize how serious this was. The 'isDeep' flag is unfortunately of no help here, because the problem is not with Address and its underlying hierarchy (controlled by 'isDeep' flag) but because of the generated SQL statement which obviously doesn't take into account the sub-entities for entity Person: SELECT DISTINCT t0.ID, t0.FK_PERSON=20 FROM ADDRESS t0, PERSON t1 WHERE ( PERSON.ID =3D 1 ) AND ( ADDRESS.FK_PERSON =3D PERSON.ID ) I've just submitted bug item #1017127 at https://sourceforge.net/tracker/index.php?func=3Ddetail&aid=3D1017127&group= _id=3D58935&atid=3D489335, with your model and the corresponding code attached. I'll search a definitive fix soon --my current thinking being about the way that would allow even more complicated qualifiers to be correctly handled as well, such as with: person.addresses.id in [2,3] or w/ a qualifier traversing two or more relationships involving entities with sub-entities. Thanks a lot for the precise report,=20 -- S=E9bastien. |
From: Sebastien B. <sbi...@us...> - 2004-08-30 21:09:16
|
I'm currently working on the issue, I thought I could share my current thoughts. So the problem w/ bug #1017127 is that the generated SQL is: > SELECT DISTINCT t0.ID, t0.FK_PERSON=20 > FROM ADDRESS t0, PERSON t1 > WHERE ( PERSON.ID =3D 1 ) AND ( ADDRESS.FK_PERSON =3D PERSON.ID ) while it should take into account the class hierarchy, so that both PERSON and EMPLOYEE are traversed. I was initially thinking of making as many SQL queries as there are pssible paths through the relationships (here, two: ADDRESS to PERSON, and ADDRESS to EMPLOYEE) --but then I remembered these could SQL queries could be UNIONed So: ec.fetch('Address', 'Person.id =3D=3D 1') should trigger the following query on the database [1]: SELECT DISTINCT t0.ID, t0.FK_PERSON FROM ADDRESS t0 INNER JOIN EMPLOYEE t1 ON t0.FK_PERSON=3Dt1.ID WHERE t1.ID =3D 1 UNION SELECT DISTINCT t0.ID, t0.FK_PERSON FROM ADDRESS t0 INNER JOIN PERSON t1 ON t0.FK_PERSON=3Dt1.ID WHERE t1.ID =3D 1 NB: Incidentally, that UNION thing could also be a solution for the current limitation of sort orderings that cannot be used w/ the isDeep flag being set! Another story, though Now the question is: suppose I have two plus two paths in the same fetch spec., such as in: AND: ec.fetch('Address', 'person.id in [1,2,3] AND person.x.y like...') OR: ec.fetch('Address', 'person.id in [1,2,3] OR person.x.y like...') --> In the case of the 'AND' operator, do the two 'Person' refer to the same table? In other words, do we get only two SELECTs union'ed? In the case of the 'OR' operator, do the two 'Person' refer independant tables, either the same or different ones? In other words, do we get 2*2=3D4 SELECTs union'ed?=20=20=20 NB: 2=3D=3Dlen([Person, Employee]) Is this what we want here, I fear I could miss something here? Any comments will be appreciated!! -- S=E9bastien. [1] w/ INNER JOINs or the equivalent WHERE clause if inner joins aint supported. Sebastien Bigaret <sbi...@us...> writes: > John Lenton <jl...@gm...> wrote: > > On 29 Jul 2004 10:30:02 +0200, Sebastien Bigaret > > <sbi...@us...> wrote: > > >=20 > > > Again, could you be a little more explicit, or exhibit a short > > > example? Sorry for getting back on this, but the only way I think th= is > > > can happen is the one I already posted (see below); if it's not the > > > case, this is a serious bug I definitely do not want to let escape. > >=20 > > sorry for the delay in answering, and the confusion when doing so. I > > feel terribly embarrassed :( >=20 > Please don't feel embarrassed, that was worth waiting for it. >=20 > > HOWever, here goes. > >=20 > > With the attached model (which is ugly, and breaks some of your naming > > conventions, but I just hacked out the attributes and renamed things > > from the model being used by a team I'm helping to get up to speed), > > using vainilla MDL 0.9-pre17.1 and NF 0.7: > >=20 > >=20 > > >>> from Modeling.EditingContext import EditingContext > > >>> import Store > > >>> ec=3DEditingContext() > > >>> ec.fetch('Address')[0] > > <Address.Address object at 0x4071c74c> > > >>> a =3D _ > > >>> p =3D ec.fetch('Person', isDeep=3D1)[0] > > <Employee.Employee object at 0x4072d88c> > > >>> p =3D _ > > >>> a.getPerson() > > <Employee.Employee object at 0x4072d88c> > > >>> a.getPerson().getId() > > 1 > > >>> a.isFault() > > False > > >>> p.getAddress() > > <Modeling.FaultHandler.AccessArrayFaultHandler instance at 0x40733a4c> > > >>> list(p.getAddress()) > > [<Address.Address object at 0x4071c74c>] > > >>> ec.fetch('Address', 'Person.id =3D=3D 1') > > [] > > >>> ec.fetch('Address', 'Person.id =3D=3D 1', isDeep=3D1) > > [] >=20 > Wooo, I didn't even realize how serious this was. The 'isDeep' flag > is unfortunately of no help here, because the problem is not with > Address and its underlying hierarchy (controlled by 'isDeep' flag) but > because of the generated SQL statement which obviously doesn't take > into account the sub-entities for entity Person: >=20 > SELECT DISTINCT t0.ID, t0.FK_PERSON=20 > FROM ADDRESS t0, PERSON t1 > WHERE ( PERSON.ID =3D 1 ) AND ( ADDRESS.FK_PERSON =3D PERSON.ID ) >=20 > I've just submitted bug item #1017127 at > https://sourceforge.net/tracker/index.php?func=3Ddetail&aid=3D1017127&gro= up_id=3D58935&atid=3D489335, > with your model and the corresponding code attached. >=20 > I'll search a definitive fix soon --my current thinking being about > the way that would allow even more complicated qualifiers to be > correctly handled as well, such as with: person.addresses.id in [2,3] > or w/ a qualifier traversing two or more relationships involving > entities with sub-entities. >=20 > Thanks a lot for the precise report,=20 >=20 > -- S=E9bastien. |
From: John L. <jl...@gm...> - 2004-08-30 22:08:13
|
On 30 Aug 2004 23:09:40 +0200, Sebastien Bigaret <sbi...@us...> wrote: > > I'm currently working on the issue, I thought I could share my current > thoughts. > > So the problem w/ bug #1017127 is that the generated SQL is: > > SELECT DISTINCT t0.ID, t0.FK_PERSON > > FROM ADDRESS t0, PERSON t1 > > WHERE ( PERSON.ID = 1 ) AND ( ADDRESS.FK_PERSON = PERSON.ID ) > > while it should take into account the class hierarchy, so that both > PERSON and EMPLOYEE are traversed. > > I was initially thinking of making as many SQL queries as there are > pssible paths through the relationships (here, two: ADDRESS to PERSON, > and ADDRESS to EMPLOYEE) --but then I remembered these could SQL queries > could be UNIONed > > So: > ec.fetch('Address', 'Person.id == 1') > > should trigger the following query on the database [1]: > > SELECT DISTINCT t0.ID, t0.FK_PERSON > FROM ADDRESS t0 > INNER JOIN EMPLOYEE t1 ON t0.FK_PERSON=t1.ID > WHERE t1.ID = 1 > UNION > SELECT DISTINCT t0.ID, t0.FK_PERSON > FROM ADDRESS t0 > INNER JOIN PERSON t1 ON t0.FK_PERSON=t1.ID > WHERE t1.ID = 1 > > NB: Incidentally, that UNION thing could also be a solution for the > current limitation of sort orderings that cannot be used w/ the > isDeep flag being set! Another story, though yes, I was going to mention that in the other thread, but then I saw that it involved modifying code all the way down to the database adapter, and thought you'd be against it. Glad to know you aren't; you do realize this will mean you need a second query to get at attributes not present in the base class? Or would you select with the union of all attributes, providing dummy values for those not present in each table? > Now the question is: suppose I have two plus two paths in the same fetch > spec., such as in: > > AND: > ec.fetch('Address', 'person.id in [1,2,3] AND person.x.y like...') > > OR: > ec.fetch('Address', 'person.id in [1,2,3] OR person.x.y like...') > > --> In the case of the 'AND' operator, do the two 'Person' refer to the > same table? In other words, do we get only two SELECTs union'ed? > > In the case of the 'OR' operator, do the two 'Person' refer > independant tables, either the same or different ones? In other > words, do we get 2*2=4 SELECTs union'ed? if we were able to do sub-selects, we would (or could) write either as SELECT * FROM (SELECT * FROM Person UNION SELECT ... FROM Employee ) AS Person WHERE <qualifier> (because that is what we mean, right?) and this reduces to SELECT * FROM Person WHERE <qualifier> UNION \ SELECT ... FROM Employee WHERE <qualifier> irrespective of <qualifier>. > Is this what we want here, I fear I could miss something here? Any > comments will be appreciated!! HTH---maybe it's me missing something, however; the "that is what we mean" assumption is a strong one (in that it has big consquences). -- John Lenton (jl...@gm...) -- Random fortune: bash: fortune: command not found |