You can subscribe to this list here.
2002 |
Jan
(2) |
Feb
(157) |
Mar
(111) |
Apr
(61) |
May
(68) |
Jun
(45) |
Jul
(101) |
Aug
(132) |
Sep
(148) |
Oct
(227) |
Nov
(141) |
Dec
(285) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2003 |
Jan
(518) |
Feb
(462) |
Mar
(390) |
Apr
(488) |
May
(321) |
Jun
(336) |
Jul
(268) |
Aug
(374) |
Sep
(211) |
Oct
(246) |
Nov
(239) |
Dec
(173) |
2004 |
Jan
(110) |
Feb
(131) |
Mar
(85) |
Apr
(120) |
May
(82) |
Jun
(101) |
Jul
(54) |
Aug
(65) |
Sep
(94) |
Oct
(51) |
Nov
(56) |
Dec
(168) |
2005 |
Jan
(146) |
Feb
(98) |
Mar
(75) |
Apr
(118) |
May
(85) |
Jun
(75) |
Jul
(44) |
Aug
(94) |
Sep
(70) |
Oct
(84) |
Nov
(115) |
Dec
(52) |
2006 |
Jan
(113) |
Feb
(83) |
Mar
(217) |
Apr
(158) |
May
(219) |
Jun
(218) |
Jul
(189) |
Aug
(39) |
Sep
(3) |
Oct
(7) |
Nov
(4) |
Dec
(2) |
2007 |
Jan
|
Feb
(2) |
Mar
(7) |
Apr
(3) |
May
(3) |
Jun
(8) |
Jul
(1) |
Aug
(1) |
Sep
|
Oct
(4) |
Nov
(7) |
Dec
|
2008 |
Jan
(1) |
Feb
(1) |
Mar
|
Apr
|
May
|
Jun
|
Jul
(2) |
Aug
(4) |
Sep
|
Oct
(2) |
Nov
(1) |
Dec
|
2009 |
Jan
(6) |
Feb
|
Mar
(1) |
Apr
(2) |
May
(1) |
Jun
(1) |
Jul
(10) |
Aug
|
Sep
(1) |
Oct
(1) |
Nov
|
Dec
(3) |
2010 |
Jan
|
Feb
(1) |
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
(2) |
Oct
|
Nov
|
Dec
|
2012 |
Jan
(1) |
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2015 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
(1) |
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: Gavin_King/Cirrus%<CI...@ci...> - 2002-03-01 08:31:48
|
> Before I go on, I want to make sure my terminology is > right. A persistent object is an object that gets > instantiated by calling Session.create(Class) and a > transient object is one created the normal way using > new. yes. Note, using create is (as of 0.9.7) no longer advantageous. its just as good to use: Foo foo = new Foo(); session.save(foo); And, in fact, this approach will sometimes be more efficient. You can now view create() as just a shortcut way of expressing the previous two lines. > Session session = ...; > Receipt receipt = > (Receipt)session.create(Receipt.class); > Product p = (Product)session.load(Product.class, new > Long(0)); > LineItem item = new LineItem(); > item.setProduct(p); > item.setQuantity(3); > receipt.addLineItem(item); > session.commit(); > Receipt contains a List of LineItem. This list is > declared in the xml, but hibernate runtime does not > persist the transient object. Is this a feature or a > bug? well, depends upon how you view it. Hibernate does *not* presently do persistence by reachability. The reasoning behind this is that *deletion* by reachability is a hard problem for an O-R mapping layer. You could try to use reference counting, but then the reference count would need to be kept in the db. (And reference counting is dodgy if you have circular references). You could try to use mark-and-sweep but the performance cost would be prohibitive. What will be implemented in a future version (Daniel has volunteered to implement this) is a "dependent" attribute in the mapping descriptor that causes saves and deletes to be cascaded. I strongly believe this to be the best solution. For now, the following code will do what you want: Session session = ...; Receipt receipt = (Receipt)session.create(Receipt.class); Product p = (Product)session.load(Product.class, new Long(0)); LineItem item = (LineItem) session.create(LineItem.class); item.setProduct(p); item.setQuantity(3); receipt.addLineItem(item); session.commit(); (Thats a 1/2 line change) Remember to explicity delete the lineitem when you delete the owning product. You can cascade deletions manually from PersistentLifecycle.delete(), if you don't want to pollute the application logic. You will be able to do it your way as soon as Daniel gets back to us ;) |
From: Son To <son...@ya...> - 2002-03-01 07:36:02
|
Before I go on, I want to make sure my terminology is right. A persistent object is an object that gets instantiated by calling Session.create(Class) and a transient object is one created the normal way using new. OK now for my question... suppose: Session session = ...; Receipt receipt = (Receipt)session.create(Receipt.class); Product p = (Product)session.load(Product.class, new Long(0)); LineItem item = new LineItem(); item.setProduct(p); item.setQuantity(3); receipt.addLineItem(item); session.commit(); Receipt contains a List of LineItem. This list is declared in the xml, but hibernate runtime does not persist the transient object. Is this a feature or a bug? thanks, son __________________________________________________ Do You Yahoo!? Yahoo! Greetings - Send FREE e-cards for every occasion! http://greetings.yahoo.com |
From: Christoph S. <ch...@sc...> - 2002-02-28 19:22:10
|
Hi gavin, all it was actually really easy, i paste it here in case someone else needs it, or you even want to put it into the tools section. <target name="initdb" depends="compile"> <java classname="cirrus.hibernate.tools.DBSchemaExport" fork="true"> <!-- mapping file --> <arg value="/projects/smis/src/resources/web/WEB-INF/mapping.xml"/> <jvmarg value="-Dhibernate.dialect=cirrus.hibernate.sql.SybaseDialect"/> <jvmarg value="-Dhibernate.driver=com.inet.tds.TdsDriver"/> <jvmarg value="-Dhibernate.url=jdbc:inetdae:localhost:1433"/> <jvmarg value="-Dhibernate.username=xxx"/> <jvmarg value="-Dhibernate.password=xxx"/> <classpath> <fileset dir="${basedir}/lib"> <include name="**/*.jar" /> </fileset> <!-- build output path --> <pathelement location="${build.dir}/classes/web/WEB-INF/classes"/> </classpath> </java> </target> Gavin_King/Cirrus%CI...@ci... wrote: > >Do we need to write an ant task for this? > >It ssupposed to be not too difficult but im not an ant expert myself. > > >_______________________________________________ >Hibernate-devel mailing list >Hib...@li... >https://lists.sourceforge.net/lists/listinfo/hibernate-devel > > |
From: Gavin_King/Cirrus%<CI...@ci...> - 2002-02-28 16:19:32
|
Do we need to write an ant task for this? It ssupposed to be not too difficult but im not an ant expert myself. |
From: Christoph S. <ch...@sc...> - 2002-02-28 15:37:27
|
Hi! Does someone have a code snippet for me how to call DBSchemaExport from ant? TIA -chris |
From: Gavin_King/Cirrus%<CI...@ci...> - 2002-02-28 09:40:50
|
I think more along the lines of: Session session = sessionFactory.openSession(); try { session.save(object); session.commit(); } catch(SQLException e) { try { session.cancel(); } catch {} .... } catch(Exception e) { try { session.cancel(); } catch {} .... } However, I believe there is a small chance of a null pointer exception from session.cancel() in the released version. I think I've got it right in CVS. I would appreciate if you could review the CVS versions of commit(), cancel (), close() in RelationalDatabaseSession and tell me if I missed anything... |
From: Gavin_King/Cirrus%<CI...@ci...> - 2002-02-28 08:46:08
|
> The documentation needs more examples. Absolutely spot on. This is a major missing feature. > I will work on the documentation as I learn > more about hibernate. I would *really* appreciate this. > In the xml map file, how to specify a non null > property? The following elements: <property>, <many-to-one>, <collection>, <element>, <many-to-many>, <subcollection>, <column> all take an attribute called not-null. ie. <property name="foo" not-null="true"/> peace Gavin |
From: Son To <son...@ya...> - 2002-02-28 04:09:14
|
Gavin, Thanks! this was what I was looking for. The documentation needs more examples. I will work on the documentation as I learn more about hibernate. In the xml map file, how to specify a non null property? thanks, Son --- Gavin_King/Cirrus%CI...@ci... wrote: > > You need to decide wether Product is a component, or > an associated object. > If its a component, it lives in the same table as > LineItem and doesn't need > its own seperate <class> mapping (the mapping is > done in the <component> > element. If Product is an entity (which i think is > what you want here), > then use: > > <many-to-one name="product" > class="openbx.domain.Product"/> > > in the mapping for LineItem. (ie. instead of > <component > ....>....</component>) > > Hope thats clear enough.... > > PS. I recommend you download the latest version it > has important bugfixes. > > > > <hibernate-mapping> > > <class name="openbx.domain.Product" > > table="product"> > > <id name="productId" column="productId" > > type="long"> > > <generator class="hilo.long"/> > > </id> > > <property name="name" type="string"/> > > <property name="price" type="double"/> > > </class> > > > > <class name="openbx.domain.LineItem" > > table="lineItems"> > > <id name="lineItemId" column="lineItemId" > > type="long"> > > <generator class="hilo.long"/> > > </id> > > <component name="product" > > class="openbx.domain.Product"> > > <property name="productId"/> > > <property name="price"/> > > </component> > > > > <property name="quantity" type="integer"/> > > </class> > > </hibernate-mapping> > > > _______________________________________________ > Hibernate-devel mailing list > Hib...@li... > https://lists.sourceforge.net/lists/listinfo/hibernate-devel __________________________________________________ Do You Yahoo!? Yahoo! Greetings - Send FREE e-cards for every occasion! http://greetings.yahoo.com |
From: Brad C. <bra...@wo...> - 2002-02-28 04:07:30
|
thanx gavin. yes i think u r right (i am getting good @ saying that :-)) btw. i wasn't referring to hibernate's own connection pooling. so assuming a datasource is being utilised, the code to do a simple object save would look something like: Session session = null; try { session = sessionFactory.openSession(); session.save(object); session.commit(); } catch(SQLException e) { .... } catch(Exception e) { .... } finally { if (session.isOpen()) { try { session.cancel(); } catch (Exception e) { .... } } } i was orginally thinking that it might be better to split out flushing & connection closing into their own public methods. however, this would make the usage of the session API more complicated, given the different connection options. need to think about this some more. so like u wrote, perhaps the best solution is adding to the documentation. a code example (something like above) with an explanation paragraph for each secenario (datasource, supplying your own connection) might do the trick. brad ----- Original Message ----- From: <Gavin_King/Cirrus%CI...@ci...> To: "Brad Clow" <bra...@wo...> Cc: <hib...@li...> Sent: Thursday, February 28, 2002 12:23 PM Subject: Re: [Hibernate-devel] datasources & connection leakage & EJB transactions > > The cancel() method should be called in a finally block. I think that > does what you require.... > > Unless you have provided your own connection, commit() and cancel() both > return the connection to the pool (either hibernate's own pool if using > DriverManager or the datasource connection pool if using a Datasource.) > At present hibernates own connection pooling algorithm is suboptimal, I > know, but it doesn't quite amount to "connection leakage". Certainly > there should be no connection leakage if using a datasource. > > The only possiblity of connection leakage is if you fail to call either > commit() or cancel() in a finally block. > > I think a big problem here is that commit() is a misleading name for > something that > > 1. Always Flushes. > 2. Sometimes closes the connection. (if using Datasource) > 3. Sometimes commits the connection. (if using DriverManager or if > using Datasource and hibernate.auto_commit=true) > > I'm open to better suggestions ( can always deprecate commit() ), but > perhaps the solution lies in better documentation. > > I mean really this method has confusing semantics so I'm really open to > alternatives. > > > in the situation where u supply a jdbc connection to hibernate, u can > always > > guarentee that the connection will be closed in a timely manner by > calling > > the close method on the connection inside a finally block. however if u > let > > hibernate open a connection for u, there is no way u can do this. i c > that > > RelationalDatabaseSession.java has a finalize method that cleans up the > > connection (which is good), but there is no guarentee as to when the gc > will > > run, and therefore when the finalize method will be called. perhaps a > > session.close method is in order? > > > |
From: Gavin_King/Cirrus%<CI...@ci...> - 2002-02-28 02:35:26
|
The cancel() method should be called in a finally block. I think that does what you require.... Unless you have provided your own connection, commit() and cancel() both return the connection to the pool (either hibernate's own pool if using DriverManager or the datasource connection pool if using a Datasource.) At present hibernates own connection pooling algorithm is suboptimal, I know, but it doesn't quite amount to "connection leakage". Certainly there should be no connection leakage if using a datasource. The only possiblity of connection leakage is if you fail to call either commit() or cancel() in a finally block. I think a big problem here is that commit() is a misleading name for something that 1. Always Flushes. 2. Sometimes closes the connection. (if using Datasource) 3. Sometimes commits the connection. (if using DriverManager or if using Datasource and hibernate.auto_commit=true) I'm open to better suggestions ( can always deprecate commit() ), but perhaps the solution lies in better documentation. I mean really this method has confusing semantics so I'm really open to alternatives. > in the situation where u supply a jdbc connection to hibernate, u can always > guarentee that the connection will be closed in a timely manner by calling > the close method on the connection inside a finally block. however if u let > hibernate open a connection for u, there is no way u can do this. i c that > RelationalDatabaseSession.java has a finalize method that cleans up the > connection (which is good), but there is no guarentee as to when the gc will > run, and therefore when the finalize method will be called. perhaps a > session.close method is in order? |
From: Gavin_King/Cirrus%<CI...@ci...> - 2002-02-28 02:29:01
|
You need to decide wether Product is a component, or an associated object. If its a component, it lives in the same table as LineItem and doesn't need its own seperate <class> mapping (the mapping is done in the <component> element. If Product is an entity (which i think is what you want here), then use: <many-to-one name="product" class="openbx.domain.Product"/> in the mapping for LineItem. (ie. instead of <component ....>....</component>) Hope thats clear enough.... PS. I recommend you download the latest version it has important bugfixes. > <hibernate-mapping> > <class name="openbx.domain.Product" > table="product"> > <id name="productId" column="productId" > type="long"> > <generator class="hilo.long"/> > </id> > <property name="name" type="string"/> > <property name="price" type="double"/> > </class> > > <class name="openbx.domain.LineItem" > table="lineItems"> > <id name="lineItemId" column="lineItemId" > type="long"> > <generator class="hilo.long"/> > </id> > <component name="product" > class="openbx.domain.Product"> > <property name="productId"/> > <property name="price"/> > </component> > > <property name="quantity" type="integer"/> > </class> > </hibernate-mapping> |
From: Son To <son...@ya...> - 2002-02-27 23:46:57
|
I am using java -Dhibernate.dialect=cirrus.hibernate.sql.PostgreSQLDialect cirrus.hibernate.tools.DBSchemaExport --properties=db.properties mapping.xml to generate the schema for postgresql. My mapping.xml is below. DBSchemaExport does not create a schema that forces referential integrity. It is possible to create a LineItem without a product according to the schema that is generated. How do I specify in the mapping.xml that a productId must exist in the Product table before a LineItem can be created? I am using hibernate0.9.5. Thanks for any feedback. <hibernate-mapping> <class name="openbx.domain.Product" table="product"> <id name="productId" column="productId" type="long"> <generator class="hilo.long"/> </id> <property name="name" type="string"/> <property name="price" type="double"/> </class> <class name="openbx.domain.LineItem" table="lineItems"> <id name="lineItemId" column="lineItemId" type="long"> <generator class="hilo.long"/> </id> <component name="product" class="openbx.domain.Product"> <property name="productId"/> <property name="price"/> </component> <property name="quantity" type="integer"/> </class> </hibernate-mapping> __________________________________________________ Do You Yahoo!? Yahoo! Greetings - Send FREE e-cards for every occasion! http://greetings.yahoo.com |
From: Brad C. <bra...@wo...> - 2002-02-27 23:45:15
|
yes, u r right. when i originally tried that, i didn't have the session.commit, as it didn't make sense to have to call commit on the session when u calling commit on the ejb transaction. it was after this that i looked through the hibernate code and saw the need to flush the session. i think the most misleading thing is the use of the commit method in this scenario. off the top of my head, i can think of two things that might improve this situation: 1. add a public flush method to the session that flushes the session. 2. a property to modify the behaviour of the session so that statements are executed immediately. i guess this would result in sub-optimal performance in the case of multiple operations in the same session.. brad ----- Original Message ----- From: <Gavin_King/Cirrus%CI...@ci...> To: "Brad Clow" <bra...@wo...> Cc: <hib...@li...> Sent: Wednesday, February 27, 2002 5:32 PM Subject: Re: [Hibernate-devel] EJB Transactions > > Hi Brad :) > > You need to set the property > > hibernate.auto_commit=false > > then you will get the behaviour you are looking for. > > This is (poorly) documented. I will try to make it more explicit. Its also > poorly named .... whats a better name for it? > > peace > > |
From: Brad C. <bra...@wo...> - 2002-02-27 23:44:35
|
in the situation where u supply a jdbc connection to hibernate, u can always guarentee that the connection will be closed in a timely manner by calling the close method on the connection inside a finally block. however if u let hibernate open a connection for u, there is no way u can do this. i c that RelationalDatabaseSession.java has a finalize method that cleans up the connection (which is good), but there is no guarentee as to when the gc will run, and therefore when the finalize method will be called. perhaps a session.close method is in order? brad _______________________________ brad clow chief technical officer workingmouse email: bra...@wo... web: http://www.workingmouse.com |
From: Gavin_King/Cirrus%<CI...@ci...> - 2002-02-27 12:26:57
|
ummmmmm.....ignore that last comment about caching being "not at all difficult". It *is* somewhat difficult - still doable, but not as easy as it looked at first sight. I'm pretty happy i got the issues of transaction isolation / data integrity figured. The couple of problems i ran into are to do with collections (as usual). It's going to have to work by caching a disassembled form of the object where associations and collections are represented by their keys. Grabbing an object from the cache reassembles the object from its immutable fields and these keys. Collections will have to be cached in a seperate collection cache (or, initially, not at all). |
From: Gavin_King/Cirrus%<CI...@ci...> - 2002-02-27 10:00:58
|
Its not currently possible. However, you can declare the setter method private, so theres no reason why this limitation forces you to break the encapsulation of your object. |
From: Son To <son...@ya...> - 2002-02-27 08:20:24
|
I have a class called Receipt which has a List of LineItem. Is it possible to persist the List of LineItem without having a setLineItems(List) method? My Receipt has an addLineItem(LineItem) method. From looking at the sample code and xml mapping files, this does not seem to be possible. Is it? thanks, Son __________________________________________________ Do You Yahoo!? Yahoo! Greetings - Send FREE e-cards for every occasion! http://greetings.yahoo.com |
From: Gavin_King/Cirrus%<CI...@ci...> - 2002-02-27 07:43:53
|
Hi Brad :) You need to set the property hibernate.auto_commit=false then you will get the behaviour you are looking for. This is (poorly) documented. I will try to make it more explicit. Its also poorly named .... whats a better name for it? peace |
From: Brad C. <bra...@wo...> - 2002-02-27 07:16:48
|
The procedure for writing session beans (using hibernate) that participate in EJB transactions is not immediately apparent from the documentation. Perhaps a note could be added to the documentation that specifies that for this situation, the successful way to create a transaction aware hibernate session is via: sessionFactory = datastore.buildSessionFactory(); session = sessionFactory.openSession(connection); The system properties mechanism and passing Properties to the buildSessionFactory will not work. This is due to the fact that the session.commit() (and cancel) methods behave differenently, depending on how the session was obtained. If the session was obtained using one of the properties mechanisms, than hibernate will flush the session, commit and close the connection, which breaks the EJB transaction. If the session is obtained by passing in a connection, then it is up to the user (or the EJB container, in this case) to commit the connection and the programmer to close the connection. brad _______________________________ brad clow chief technical officer workingmouse email: bra...@wo... web: http://www.workingmouse.com |
From: Gavin_King/Cirrus%<CI...@ci...> - 2002-02-27 05:46:29
|
> I understand what you're saying, and I hate to be dense, but can you > point to where in the current code you depend on or take advantage of > this feature of collection wrappers? In particular, I can't see where > the collection wrapper itself (i.e., the composition of the > collection) is rolled back. Yeah. Not dense. You just spotted a bug. ;) What is meant to happen is that if the session gets rolled back during initialization of the collection then the existing collection elements will get overwritten on the next call to read(). (ie. from RelationalDatabaseSession.initialze() ) Unfortunately this won't work at present. We need a PersistentCollection.beforeInitialize() method to get the collection ready for initialization. Do you want to fix that or shall I? This lives in the "_very_ obscure bug" category, unlike other problems fixed recently :) |
From: Doug C. <de...@fl...> - 2002-02-27 05:09:50
|
> Heres some extra issues for you: > 1. You can't keep any state, apart from actual elements and a pointer to > the session, in the collection wrapper. This is to support rollback of > the session state when an exception occurs. I understand what you're saying, and I hate to be dense, but can you point to where in the current code you depend on or take advantage of this feature of collection wrappers? In particular, I can't see where the collection wrapper itself (i.e., the composition of the collection) is rolled back. The method setCleanState seems a likely place to snapshot the collection state, but this only seems to happen for component elements and arrays (not for my example map of dates and many-to-ones for example). <snip> > single change: > * write() and read() take an argument: the index being accessed > SessionImplementor.initialize() and SessionImplementor.dirty() > also recieve that argument. The wrapper itself never knows how > fully initialized it is. This is consistent with the current > design. The CollectionEntry keeps track of which elements changed > and which are initialized. I briefly considered this design, and don't remember why I ruled it out; probably because the other idea occurred to me; but with the other issues you raised, it's beginning to look good again! e |
From: Gavin_King/Cirrus%<CI...@ci...> - 2002-02-27 04:23:28
|
Quite a few people seem to want hibernate to be able to cache data. I'm not convinced that people need this feature as much as they think they do; nevertheless, there is at least three cases where its useful * application has exclusive access to database * static data * non-critical data that is "almost" static (ie. a timeout cache is apropriate) I have added a feature request for this. It's not at all difficult to implement - we would just have RelationalDatabaseSession.load() check a cache on ClassPersister after checking its own internal cache. Then there would be a couple of places where we would need to add, replace or remove objects. William Grosso, writing in onjava.com has described a good cache expiration algorithm ("hashbelt"). Unfortunately his implementation uses a seperate thread to do expiration + uses generics, so I'll have to adapt it. There would need to be two kinds of cache: 1. A cache for readonly data where sessions can share the same object instance. 2. A cache for mutable data - only one session can use the cached instance. Unless anyone else is keen to implement this, I'll probably get onto it in the next couple of days.... PS. Is it spelled "cacheing" or "caching"? |
From: Gavin_King/Cirrus%<CI...@ci...> - 2002-02-27 03:34:24
|
This would be brilliant, Doug. I'd love to see it. I bet in real systems it would be a *much* bigger performance boost than having lazily initialized objects. > I have been thinking about "deep lazy collections." For example, a map > where only individual entries are read from the database as needed, > and only added or modified entries are written. [This is probably only > really useful for maps, and maybe sets.] I would have thought maps and *lists*?? > Of course you could create such a map by using a DATE field as the > primary key (id) for some class and using custom queries. But there is > a certain beauty in using Hibernate collections and Java accesses > directly. I agree. You don't want to write queries where you would naturally write Java. And there are other advantages to collections, like garbage collection. > I believe that deep lazy collections (lazy="deep") could be > implemented without *too* much effort. I would appreciate critiques on > my proposal... I believe its not "*too*" difficult and half of the problem (ie. only writing changed entries) has been on my secret todo list for some time (I hadn't thought of the other half.) This is not the same as saying it will be easy. Without doubt, the most difficult code in hibernate is the stuffin RelationalDatabaseSession that handles collections. I got it wrong quite a few times. The complexity is a result of: 1. arbitrarily nested subcollections 2. composite collection elements 3. persistent garbage collection 4. lazy initialization (5. collections not independantly versioned) Those four (5) things interact in wierd and wonderful ways. For example, if you want to garbage collect a collection thats not been (lazily) initialized, you have to load up not only that collection, but also all its subcollections so you can delete _them_ from the database. > 1. Deep Lazy collection classes would extend the Lazy classes in > cirrus.hibernate.collections.*. As a fallback, if the user does > something inconsistent with deep laziness, e.g., asking for a > collection of elements via Map.values() for example, the Deep Lazy > class would simply revert to Lazy behavior. > 3. Deep Lazy collection classes would maintain a number of local maps > to record additions, removals, and modifications. These maps, along > with a cache of read objects, are consulted before going to the > database. See logic and invariants below. > 4. CollectionPersister would be extended to support sql for select by > map-key, delete by map-key, and update by map-key, as well as count(*). > 5. To maintain some backward compatibility with the current > RelationalDatabaseSession and its use of dorecreate and doremove, > PersistentCollection could add methods for > isDeepLazy() => false (if true, don't delete all, instead ask for:) > deleteEntries() > insertEntries() => entries() for old collection classes > updateEntries() => null for old collection classes Heres some extra issues for you: 1. You can't keep any state, apart from actual elements and a pointer to the session, in the collection wrapper. This is to support rollback of the session state when an exception occurs. So lists of additions, removals, etc got to be kept on the CollectionEntry in RelationalDatabaseSession. It might be best to have two subclasses of CollectionEntry and try to do some things polymorphically. 2. It *might* be a good idea to move some functionality currently implemented on RelationalDatabaseSession to CollectionPersister. This would let you subclass CollectionPersister to change behaviour for deep lazy collections. On the other hand, persisters are not allowed to keep any mutable state (obviously), so that might result in lots of nasty calls to/from the session. 3. What happens when a Map starts out in a role where its doing "deep lazy" initialization and then moves to a role where its doing lazy or eager initialization? You will have the wrong wrapper class. This is a somewhat hard problem.... In light of (1) and especially (2), I would consider a different design. Continue using the current collection wrappers and make a single change: * write() and read() take an argument: the index being accessed SessionImplementor.initialize() and SessionImplementor.dirty() also recieve that argument. The wrapper itself never knows how fully initialized it is. This is consistent with the current design. The CollectionEntry keeps track of which elements changed and which are initialized. Subclass CollectionEntry and/or CollectionPersister to implement the functionality that varies between lazy and deep lazy. > There are surely some things I haven't considered or don't fully > appreciate. Some areas that concern me: > 1. The notion of ce.initialized must be refined. There will be > collections that have a persister, but have not been read entirely. > I.e., ce.initialized, but elements() not valid; see: flush, > updateReachableCollection, searchForDirtyCollections, > prepareCollectionForUpdate. > 2. prepareCollectionForUpdate must be smarter, e.g., deciding when to > totally recreate a collection versus when to update only; this may be > a separate dirty case verus a copied or moved case, I'm not sure. > 3. How does this affect copying and reusing (sub-)collections? Doug, why don't you create a new CVS branch for playing with this stuff and have a look at implementing the logic you described on CollectionEntry or a subclass. (We might need to make it a non-inner class.) |
From: Gavin_King/Cirrus%<CI...@ci...> - 2002-02-27 02:05:23
|
You can do this, it works fine - even for collections. (I added it to the test suite, just in case.) |
From: Doug C. <de...@fl...> - 2002-02-26 23:24:46
|
I have been thinking about "deep lazy collections." For example, a map where only individual entries are read from the database as needed, and only added or modified entries are written. [This is probably only really useful for maps, and maybe sets.] Deep lazy collections would be very useful for large collections that are accessed sparsely. An example might be a map keyed by date where several years worth of data are stored but only a few days worth used at any one time. Of course you could create such a map by using a DATE field as the primary key (id) for some class and using custom queries. But there is a certain beauty in using Hibernate collections and Java accesses directly. I believe that deep lazy collections (lazy="deep") could be implemented without *too* much effort. I would appreciate critiques on my proposal... 1. Deep Lazy collection classes would extend the Lazy classes in cirrus.hibernate.collections.*. As a fallback, if the user does something inconsistent with deep laziness, e.g., asking for a collection of elements via Map.values() for example, the Deep Lazy class would simply revert to Lazy behavior. 2. The methods get(), put(), remove(), size(), and a few others would be optimized to perform minimal database activity. 3. Deep Lazy collection classes would maintain a number of local maps to record additions, removals, and modifications. These maps, along with a cache of read objects, are consulted before going to the database. See logic and invariants below. 4. CollectionPersister would be extended to support sql for select by map-key, delete by map-key, and update by map-key, as well as count(*). 5. To maintain some backward compatibility with the current RelationalDatabaseSession and its use of dorecreate and doremove, PersistentCollection could add methods for isDeepLazy() => false (if true, don't delete all, instead ask for:) deleteEntries() insertEntries() => entries() for old collection classes updateEntries() => null for old collection classes There are surely some things I haven't considered or don't fully appreciate. Some areas that concern me: 1. The notion of ce.initialized must be refined. There will be collections that have a persister, but have not been read entirely. I.e., ce.initialized, but elements() not valid; see: flush, updateReachableCollection, searchForDirtyCollections, prepareCollectionForUpdate. 2. prepareCollectionForUpdate must be smarter, e.g., deciding when to totally recreate a collection versus when to update only; this may be a separate dirty case verus a copied or moved case, I'm not sure. 3. How does this affect copying and reusing (sub-)collections? Again, comments are welcome. I am willing to code the cirrus.hibernate.collections.* part of the implementation (an outline of that portion is below), and maybe the changes in CollectionPersister if we can agree on the interface to RelationalDatabaseSession. e -=- map with deep laziness dbase - the elements in the db cache - the elements looked up (unchanged from dbase version) repls - the modified elements addns - the newly created elements delts - the newly deleted elements invariants: cache is just a copy of what's in dbase an entity is only in one of: delts or addns or repls if in delts, then in dbase if in addns, then not in dbase if in repls, then in dbase logic... each of these operations searches the maps in order, and if found in ------- put - delts: remove from delts, create a repl addns: modify the addn repls: modify the repl dbase: create a repl else: create a addn rem - delts: nothing to do addns: remove from addns repls: remove from repls, add to delts dbase: create a delt else: nothing to do get - delts: not found addns: ok repls: ok dbase: ok else: not found size := dbase.sqlCount() + addns.size() - delts.size() isEmpty := count == 0 containsKey := get != null get := get remove := rem put := put putAll := put in loop the rest := revert to old mode i.e., read(); apply addns, repls, delts; wipe addns, repls, delts, cache. maybe containsElement := get(byElement?) != null -=- |