|
From: <jue...@we...> - 2003-07-29 15:01:55
|
<quote> So, we make a hashCode with some smarts. First time hashcode is called, - if id is null/zero, then hashCode will forever return the same value,=20 which is the same for all class instances. Inefficient, but doesn't=20 cause Sets to barf. - but if is not-null/zero and hashCode has never been called while id=20 was null/zero, then hashCode will retun a value based on the id. This=20 means that loaded entities loaded form the db are treated efficiently. Still not that great in terms of efficiency for new entities, but=20 efficient for old entities. </quote> Interesting idea - a hashCode implementation that tracks if it has = already been called with an empty ID... So "contains" and "remove" will = work even after saving, but unfortunately only for this very instance. = Calling "contains" with a freshly loaded instance (and the previously = saved one in the collection) will still fail, as the freshly loaded = instance will return an ID-based hash code that will not match the one = in the collection. <quote> Also, there is still an issue with any collection (ie not HashSet) that=20 uses 'equals', since that is going to change when the id changes. </quote> But that doesn't matter as such a collection will just call "equals" on = *lookup*, not on *addition*. It will always find an entity, as long as = "equals" can deal with the current state. That's not the case with = HashSet: The hash code of an object is determined within the "add" = method, and fixed from there on. Juergen |
|
From: Colin S. <col...@ex...> - 2003-08-01 17:51:59
|
I started a thread on there actually, but unfortunately I couldn't get Gavin to agree that it is worth enhancing Hibernate to support dynamic rehashing of the changed element in the Set on the id change, which I think is what is really needed... http://sourceforge.net/forum/forum.php?thread_id=909482&forum_id=128638 Timo Verhoeven wrote: >Hi! > >It might be a good idea to discuss these issues on the hibernate >forums/mailing lists. I could imagine, there are others who had these >problems before. > > >Regards, > >Timo > >Am Dienstag, 29. Juli 2003 17:18 schrieb Colin Sampaleanu: > > >>jürgen höller [werk3AT] wrote: >> >> >>><quote> >>>So, we make a hashCode with some smarts. First time hashcode is >>>called, - if id is null/zero, then hashCode will forever return the >>>same value, which is the same for all class instances. Inefficient, >>>but doesn't cause Sets to barf. >>>- but if is not-null/zero and hashCode has never been called while >>>id was null/zero, then hashCode will retun a value based on the id. >>>This means that loaded entities loaded form the db are treated >>>efficiently. >>> >>>Still not that great in terms of efficiency for new entities, but >>>efficient for old entities. >>></quote> >>> >>>Interesting idea - a hashCode implementation that tracks if it has >>>already been called with an empty ID... So "contains" and "remove" >>>will work even after saving, but unfortunately only for this very >>>instance. Calling "contains" with a freshly loaded instance (and >>>the previously saved one in the collection) will still fail, as the >>>freshly loaded instance will return an ID-based hash code that will >>>not match the one in the collection. >>> >>> >>Hmm, I think your point shows that this technique is somewhat >>dangerous. I think it might break Hibernate's saveOrUpdate >>functionality in some cases. You can not have a new object which is >>added to a session (therefore it had an empty id and was added as >>such to the collection, and then come along with a transient version >>of the same object (which was built up in a different order (ie not >>added to a collection before the id was set), coming in as a child >>in a collection inside a parent object, and call saveOrUpdate >>reliably. That is, Hibernate would know if the object needs to be >>saved or updated ok, but on an update would not be able to get the >>same initial instance to update. >> >>bummer... >> >> >> >>><quote> >>>Also, there is still an issue with any collection (ie not HashSet) >>>that uses 'equals', since that is going to change when the id >>>changes. </quote> >>> >>>But that doesn't matter as such a collection will just call "equals" >>>on *lookup*, not on *addition*. It will always find an entity, as >>>long as "equals" can deal with the current state. That's not the >>>case with HashSet: The hash code of an object is determined within >>>the "add" method, and fixed from there on. >>> >>>Juergen >>> >>> |
|
From: Timo V. <sic...@gm...> - 2003-08-01 18:45:47
|
Hi! I think I know another safe solution... which has its own drawbacks, of=20 course: Given I want to use native db sequences and I use DAOs in my app-design,=20 I could disallow access to all domain objects' (objects to be=20 persisted) constructors and insert a 'newInstance' method for each=20 domain object in a/the DAO. This 'newInstance' method would call the=20 constructor, then access the native db sequence for the next value,=20 change the id in the newly created instance, and return that instance.=20 As far as I see it, this should "do it". Drawbacks:=20 =2D You can no longer create new domain object instances easily outside=20 your app (/appserver), say in a remote Client accessing your EJB-app. =2D Each and every domain object instance now needs one additional db=20 access at instantiation time. =2D There will be "holes" in your database tables when you look at the id=20 sequences when you create a domain object instance that will be dropped=20 without persisting it. =2D I'm not sure if the special m:n is handled correctly.... =2D Using autoincrement columns with this approach might not be as easy as= =20 using sequences. Have I missed something? Opinions? Regards, Timo Am Freitag, 1. August 2003 19:51 schrieb Colin Sampaleanu: > I started a thread on there actually, but unfortunately I couldn't > get Gavin to agree that it is worth enhancing Hibernate to support > dynamic rehashing of the changed element in the Set on the id change, > which I think is what is really needed... > > http://sourceforge.net/forum/forum.php?thread_id=3D909482&forum_id=3D1286 >38 > > Timo Verhoeven wrote: > >Hi! > > > >It might be a good idea to discuss these issues on the hibernate > >forums/mailing lists. I could imagine, there are others who had > > these problems before. > > > > > >Regards, > > > >Timo > > > >Am Dienstag, 29. Juli 2003 17:18 schrieb Colin Sampaleanu: > >>j=FCrgen h=F6ller [werk3AT] wrote: > >>><quote> > >>>So, we make a hashCode with some smarts. First time hashcode is > >>>called, - if id is null/zero, then hashCode will forever return > >>> the same value, which is the same for all class instances. > >>> Inefficient, but doesn't cause Sets to barf. > >>>- but if is not-null/zero and hashCode has never been called while > >>>id was null/zero, then hashCode will retun a value based on the > >>> id. This means that loaded entities loaded form the db are > >>> treated efficiently. > >>> > >>>Still not that great in terms of efficiency for new entities, but > >>>efficient for old entities. > >>></quote> > >>> > >>>Interesting idea - a hashCode implementation that tracks if it has > >>>already been called with an empty ID... So "contains" and "remove" > >>>will work even after saving, but unfortunately only for this very > >>>instance. Calling "contains" with a freshly loaded instance (and > >>>the previously saved one in the collection) will still fail, as > >>> the freshly loaded instance will return an ID-based hash code > >>> that will not match the one in the collection. > >> > >>Hmm, I think your point shows that this technique is somewhat > >>dangerous. I think it might break Hibernate's saveOrUpdate > >>functionality in some cases. You can not have a new object which is > >>added to a session (therefore it had an empty id and was added as > >>such to the collection, and then come along with a transient > >> version of the same object (which was built up in a different > >> order (ie not added to a collection before the id was set), coming > >> in as a child in a collection inside a parent object, and call > >> saveOrUpdate reliably. That is, Hibernate would know if the object > >> needs to be saved or updated ok, but on an update would not be > >> able to get the same initial instance to update. > >> > >>bummer... > >> > >>><quote> > >>>Also, there is still an issue with any collection (ie not HashSet) > >>>that uses 'equals', since that is going to change when the id > >>>changes. </quote> > >>> > >>>But that doesn't matter as such a collection will just call > >>> "equals" on *lookup*, not on *addition*. It will always find an > >>> entity, as long as "equals" can deal with the current state. > >>> That's not the case with HashSet: The hash code of an object is > >>> determined within the "add" method, and fixed from there on. > >>> > >>>Juergen > > ------------------------------------------------------- > This SF.Net email sponsored by: Free pre-built ASP.NET sites > including Data Reports, E-commerce, Portals, and Forums are available > now. Download today and enter to win an XBOX or Visual Studio .NET. > http://aspnet.click-url.com/go/psa00100003ave/direct;at.aspnet_072303 >_01/01 _______________________________________________ > Springframework-developer mailing list > Spr...@li... > https://lists.sourceforge.net/lists/listinfo/springframework-develope >r |
|
From: Colin S. <col...@ex...> - 2003-08-01 18:58:15
|
I was discussing this option with somebody the other day. You actually don't necessarilly need to hit the db for each new object id. You could use the standard hi-lo or variation of technique, where a sequence provides the low word and then the high word comes from in memory, from some sort of singleton. So you end up hitting the db on only every 100 ids, etc. Of course, this does mean that there are all sorts of holes in your ids, and large values. As you say, there is the disadvantage that a tier that is disconnected from the db can no longer use this technique (although potentially that tier could ask for a bunch of ids from the remote tier). The other disadvantage for Hibernate use would be that you would no longer have a distinguising unsaved entity id value, since there would be a valid id in the entity. The only way I can think to get around this and still use saveOrUpdate, is to use a Hibernate Interceptor, and use another property in the entity which says whether it is saved or not. I already use this for an entity with a composite id key, so it's a workable solution. Timo Verhoeven wrote: >Hi! > >I think I know another safe solution... which has its own drawbacks, of >course: > >Given I want to use native db sequences and I use DAOs in my app-design, >I could disallow access to all domain objects' (objects to be >persisted) constructors and insert a 'newInstance' method for each >domain object in a/the DAO. This 'newInstance' method would call the >constructor, then access the native db sequence for the next value, >change the id in the newly created instance, and return that instance. >As far as I see it, this should "do it". > >Drawbacks: >- You can no longer create new domain object instances easily outside >your app (/appserver), say in a remote Client accessing your EJB-app. >- Each and every domain object instance now needs one additional db >access at instantiation time. >- There will be "holes" in your database tables when you look at the id >sequences when you create a domain object instance that will be dropped >without persisting it. >- I'm not sure if the special m:n is handled correctly.... >- Using autoincrement columns with this approach might not be as easy as >using sequences. > >Have I missed something? Opinions? > > >Regards, > >Timo > >Am Freitag, 1. August 2003 19:51 schrieb Colin Sampaleanu: > > >>I started a thread on there actually, but unfortunately I couldn't >>get Gavin to agree that it is worth enhancing Hibernate to support >>dynamic rehashing of the changed element in the Set on the id change, >>which I think is what is really needed... >> >>http://sourceforge.net/forum/forum.php?thread_id=909482&forum_id=1286 >>38 >> >>Timo Verhoeven wrote: >> >> >>>Hi! >>> >>>It might be a good idea to discuss these issues on the hibernate >>>forums/mailing lists. I could imagine, there are others who had >>>these problems before. >>> >>> >>>Regards, >>> >>>Timo >>> >>>Am Dienstag, 29. Juli 2003 17:18 schrieb Colin Sampaleanu: >>> >>> >>>>jürgen höller [werk3AT] wrote: >>>> >>>> >>>>><quote> >>>>>So, we make a hashCode with some smarts. First time hashcode is >>>>>called, - if id is null/zero, then hashCode will forever return >>>>>the same value, which is the same for all class instances. >>>>>Inefficient, but doesn't cause Sets to barf. >>>>>- but if is not-null/zero and hashCode has never been called while >>>>>id was null/zero, then hashCode will retun a value based on the >>>>>id. This means that loaded entities loaded form the db are >>>>>treated efficiently. >>>>> >>>>>Still not that great in terms of efficiency for new entities, but >>>>>efficient for old entities. >>>>></quote> >>>>> >>>>>Interesting idea - a hashCode implementation that tracks if it has >>>>>already been called with an empty ID... So "contains" and "remove" >>>>>will work even after saving, but unfortunately only for this very >>>>>instance. Calling "contains" with a freshly loaded instance (and >>>>>the previously saved one in the collection) will still fail, as >>>>>the freshly loaded instance will return an ID-based hash code >>>>>that will not match the one in the collection. >>>>> >>>>> >>>>Hmm, I think your point shows that this technique is somewhat >>>>dangerous. I think it might break Hibernate's saveOrUpdate >>>>functionality in some cases. You can not have a new object which is >>>>added to a session (therefore it had an empty id and was added as >>>>such to the collection, and then come along with a transient >>>>version of the same object (which was built up in a different >>>>order (ie not added to a collection before the id was set), coming >>>>in as a child in a collection inside a parent object, and call >>>>saveOrUpdate reliably. That is, Hibernate would know if the object >>>>needs to be saved or updated ok, but on an update would not be >>>>able to get the same initial instance to update. >>>> >>>>bummer... >>>> >>>> >>>> >>>>><quote> >>>>>Also, there is still an issue with any collection (ie not HashSet) >>>>>that uses 'equals', since that is going to change when the id >>>>>changes. </quote> >>>>> >>>>>But that doesn't matter as such a collection will just call >>>>>"equals" on *lookup*, not on *addition*. It will always find an >>>>>entity, as long as "equals" can deal with the current state. >>>>>That's not the case with HashSet: The hash code of an object is >>>>>determined within the "add" method, and fixed from there on. >>>>> >>>>>Juergen >>>>> >>>>> >>------------------------------------------------------- >>This SF.Net email sponsored by: Free pre-built ASP.NET sites >>including Data Reports, E-commerce, Portals, and Forums are available >>now. Download today and enter to win an XBOX or Visual Studio .NET. >>http://aspnet.click-url.com/go/psa00100003ave/direct;at.aspnet_072303 >>_01/01 _______________________________________________ >>Springframework-developer mailing list >>Spr...@li... >>https://lists.sourceforge.net/lists/listinfo/springframework-develope >>r >> >> > > > >------------------------------------------------------- >This SF.Net email sponsored by: Free pre-built ASP.NET sites including >Data Reports, E-commerce, Portals, and Forums are available now. >Download today and enter to win an XBOX or Visual Studio .NET. >http://aspnet.click-url.com/go/psa00100003ave/direct;at.aspnet_072303_01/01 >_______________________________________________ >Springframework-developer mailing list >Spr...@li... >https://lists.sourceforge.net/lists/listinfo/springframework-developer > > |
|
From: Timo V. <sic...@gm...> - 2003-08-08 08:41:41
|
Hi all!
I think I finally have a solution to the hashCode/equals problems!
In every table I have a field/property named "created" of type datetime,
which may not be null. My domain objects hence all have a "created"
property, which is initialized with the current time on instantiation
("new java.util.Date()"). Other applications using the database
directly MUST supply values for "created" (be they bogus or not).
"created" may not be altered once set, which could even be enforced
with the use of triggers/permissions on the DB side and a private
setCreated() method on the Java side.
Now I "calculate" hashCode() based on the "created" property (invoke
getCreated().hashCode()) and equals() still based on ID.
This should solve all problems issued before!
Opinions? Have I missed anything?
Regards,
Timo
|
|
From: Rob B. <rob...@ve...> - 2003-08-08 13:11:23
|
Timo,
You may run into problems with that solution. Depending upon the precision of how the data is stored in your database, you may have a wide window where multiple objects have the same date.
Let's just say, for sake of arguement, that your database only holds date to the nearest second, and loses any sub-second accuracy. If two objects are created within the same second in your app, and then stored to the DB, when they are pulled back they will have the same created time, and thus your code will think they are the same object.
If you want a better solution for this scheme of generating a hashcode, use a GUID / UUID generator. These take time / machine (usually IP address in Java, network card MAC address in C.) and usually other "unique/random" parameters into account for creating an ID. Using a good GUID / UUID generator with a good algorithm will GUARANTEE that no two id's are the same, without the need for any synchronization between machines (like hi/low, sequence, etc require). Since Java based GUID / UUID generators generally use the machines IP address as part of the algorithm, you need to be sure that the IP address of each machine is unique. This is usually not a problem in a lan / lan cluster environment. Also make sure your algorithm doesn't mistakenly use 127.0.0.1 as it's IP address, as all machines have that IP.
Hope this helps out.
Later
Rob
>
>
> Hi all!
>
> I think I finally have a solution to the hashCode/equals problems!
>
> In every table I have a field/property named "created" of type datetime,
> which may not be null. My domain objects hence all have a "created"
> property, which is initialized with the current time on instantiation
> ("new java.util.Date()"). Other applications using the database
> directly MUST supply values for "created" (be they bogus or not).
> "created" may not be altered once set, which could even be enforced
> with the use of triggers/permissions on the DB side and a private
> setCreated() method on the Java side.
>
> Now I "calculate" hashCode() based on the "created" property (invoke
> getCreated().hashCode()) and equals() still based on ID.
>
> This should solve all problems issued before!
>
> Opinions? Have I missed anything?
>
>
> Regards,
>
> Timo
|
|
From: Timo V. <sic...@gm...> - 2003-08-08 13:36:21
|
Hi! > You may run into problems with that solution. Depending upon the > precision of how the data is stored in your database, you may have a > wide window where multiple objects have the same date. > > Let's just say, for sake of arguement, that your database only holds > date to the nearest second, and loses any sub-second accuracy. If > two objects are created within the same second in your app, and then > stored to the DB, when they are pulled back they will have the same > created time, and thus your code will think they are the same object. I don't thinks there's a problem: As I said, equals() is still id based, only hashCode() is "created" based. And its no problem that differerent (according to equals()) instances have the same hashCode(). It perfectly holds the contract! The database just should not truncate any bits! Otherwise there will be problems, of course. > If you want a better solution for this scheme of generating a > hashcode, use a GUID / UUID generator. These take time / machine > (usually IP address in Java, network card MAC address in C.) and > usually other "unique/random" parameters into account for creating an > ID. Using a good GUID / UUID generator with a good algorithm will > GUARANTEE that no two id's are the same, without the need for any > synchronization between machines (like hi/low, sequence, etc > require). Since Java based GUID / UUID generators generally use the > machines IP address as part of the algorithm, you need to be sure > that the IP address of each machine is unique. This is usually not a > problem in a lan / lan cluster environment. Also make sure your > algorithm doesn't mistakenly use 127.0.0.1 as it's IP address, as all > machines have that IP. I don't want to use GUIDs in some cases. I sometimes HAVE to use database native sequences/autovalues. Regards, Timo |
|
From: Timo V. <sic...@gm...> - 2003-08-08 13:53:58
|
> I don't thinks there's a problem: As I said, equals() is still id > based, only hashCode() is "created" based. And its no problem that > differerent (according to equals()) instances have the same > hashCode(). It perfectly holds the contract! The database just should > not truncate any bits! Otherwise there will be problems, of course. One more thing: Basically you could base the hashCode on any UNMODIFIEABLE random value, as long as its initialized on object construction. BUT the creation time is a good thing for me, since I store/use it anyway. |
|
From: Colin S. <col...@ex...> - 2003-07-29 15:18:39
|
jürgen höller [werk3AT] wrote: ><quote> >So, we make a hashCode with some smarts. First time hashcode is called, >- if id is null/zero, then hashCode will forever return the same value, >which is the same for all class instances. Inefficient, but doesn't >cause Sets to barf. >- but if is not-null/zero and hashCode has never been called while id >was null/zero, then hashCode will retun a value based on the id. This >means that loaded entities loaded form the db are treated efficiently. > >Still not that great in terms of efficiency for new entities, but >efficient for old entities. ></quote> > >Interesting idea - a hashCode implementation that tracks if it has already been called with an empty ID... So "contains" and "remove" will work even after saving, but unfortunately only for this very instance. Calling "contains" with a freshly loaded instance (and the previously saved one in the collection) will still fail, as the freshly loaded instance will return an ID-based hash code that will not match the one in the collection. > Hmm, I think your point shows that this technique is somewhat dangerous. I think it might break Hibernate's saveOrUpdate functionality in some cases. You can not have a new object which is added to a session (therefore it had an empty id and was added as such to the collection, and then come along with a transient version of the same object (which was built up in a different order (ie not added to a collection before the id was set), coming in as a child in a collection inside a parent object, and call saveOrUpdate reliably. That is, Hibernate would know if the object needs to be saved or updated ok, but on an update would not be able to get the same initial instance to update. bummer... > ><quote> >Also, there is still an issue with any collection (ie not HashSet) that >uses 'equals', since that is going to change when the id changes. ></quote> > >But that doesn't matter as such a collection will just call "equals" on *lookup*, not on *addition*. It will always find an entity, as long as "equals" can deal with the current state. That's not the case with HashSet: The hash code of an object is determined within the "add" method, and fixed from there on. > >Juergen > > >------------------------------------------------------- >This SF.Net email sponsored by: Free pre-built ASP.NET sites including >Data Reports, E-commerce, Portals, and Forums are available now. >Download today and enter to win an XBOX or Visual Studio .NET. >http://aspnet.click-url.com/go/psa00100003ave/direct;at.aspnet_072303_01/01 >_______________________________________________ >Springframework-developer mailing list >Spr...@li... >https://lists.sourceforge.net/lists/listinfo/springframework-developer > > |
|
From: Timo V. <sic...@gm...> - 2003-08-01 17:05:23
|
Hi! It might be a good idea to discuss these issues on the hibernate=20 forums/mailing lists. I could imagine, there are others who had these=20 problems before. Regards, Timo Am Dienstag, 29. Juli 2003 17:18 schrieb Colin Sampaleanu: > j=FCrgen h=F6ller [werk3AT] wrote: > ><quote> > >So, we make a hashCode with some smarts. First time hashcode is > > called, - if id is null/zero, then hashCode will forever return the > > same value, which is the same for all class instances. Inefficient, > > but doesn't cause Sets to barf. > >- but if is not-null/zero and hashCode has never been called while > > id was null/zero, then hashCode will retun a value based on the id. > > This means that loaded entities loaded form the db are treated > > efficiently. > > > >Still not that great in terms of efficiency for new entities, but > >efficient for old entities. > ></quote> > > > >Interesting idea - a hashCode implementation that tracks if it has > > already been called with an empty ID... So "contains" and "remove" > > will work even after saving, but unfortunately only for this very > > instance. Calling "contains" with a freshly loaded instance (and > > the previously saved one in the collection) will still fail, as the > > freshly loaded instance will return an ID-based hash code that will > > not match the one in the collection. > > Hmm, I think your point shows that this technique is somewhat > dangerous. I think it might break Hibernate's saveOrUpdate > functionality in some cases. You can not have a new object which is > added to a session (therefore it had an empty id and was added as > such to the collection, and then come along with a transient version > of the same object (which was built up in a different order (ie not > added to a collection before the id was set), coming in as a child=20 > in a collection inside a parent object, and call saveOrUpdate > reliably. That is, Hibernate would know if the object needs to be > saved or updated ok, but on an update would not be able to get the > same initial instance to update. > > bummer... > > ><quote> > >Also, there is still an issue with any collection (ie not HashSet) > > that uses 'equals', since that is going to change when the id > > changes. </quote> > > > >But that doesn't matter as such a collection will just call "equals" > > on *lookup*, not on *addition*. It will always find an entity, as > > long as "equals" can deal with the current state. That's not the > > case with HashSet: The hash code of an object is determined within > > the "add" method, and fixed from there on. > > > >Juergen > > > > > >------------------------------------------------------- > >This SF.Net email sponsored by: Free pre-built ASP.NET sites > > including Data Reports, E-commerce, Portals, and Forums are > > available now. Download today and enter to win an XBOX or Visual > > Studio .NET. > > http://aspnet.click-url.com/go/psa00100003ave/direct;at.aspnet_0723 > >03_01/01 _______________________________________________ > >Springframework-developer mailing list > >Spr...@li... > >https://lists.sourceforge.net/lists/listinfo/springframework-develop > >er > > ------------------------------------------------------- > This SF.Net email sponsored by: Free pre-built ASP.NET sites > including Data Reports, E-commerce, Portals, and Forums are available > now. Download today and enter to win an XBOX or Visual Studio .NET. > http://aspnet.click-url.com/go/psa00100003ave/direct;at.aspnet_072303 >_01/01 _______________________________________________ > Springframework-developer mailing list > Spr...@li... > https://lists.sourceforge.net/lists/listinfo/springframework-develope >r |