Steve Conklin
developer at ultradnt.com
Mon Mar 13 09:36:13 CST 2006
I have been following this thread with great interest. When faced with this issue, I have gone completely the opposite direction - that is not bleeding edge but back to Access basics. This was in an Access FE, MSSQL BE. Doing unbound in a "header" record (invoice, for instance) is pretty straightforward, especially when starting with a bound form and then deleting the record source property, so all controls have the same name as fields. The details in the subform (invoice line-items) are another matter. After several failed attempts at a disconnected ADO recordset, I thought about arrays, dictionaries, collections, converting somehow ADO to DOA at runtime, but finally came back to Access iteslf - I had the best device ever created for holding columns and rows of data: Access' own Tables! They provide nearly code-free storage, easy creation of new rows, are easily displayed in bound sub forms, etc. I appended all the tbl_invoice_details to tbl_invoice_details_local - which has the exact same structure, except that the pk-autonumber field in the local is neither. It is a long with a default of 0 (indicates new when writing back). Also added a y/n field to indicate "deleted" (sub form filters for deleted=0). This is decidedly low-tech as compared to serializing XML streams and such, and also requires home-grown locking (I added a bit field to invoice to indicate "in use"), but it does work by virtue of staying in Access sweet-spot rather than venturing in to uncharted waters. Steve -----Original Message----- From: accessd-bounces at databaseadvisors.com [mailto:accessd-bounces at databaseadvisors.com] On Behalf Of Shamil Salakhetdinov Sent: Monday, March 13, 2006 10:00 AM To: Access Developers discussion and problem solving Subject: Re: [AccessD] Access XP forms bound to ADO recordsets > Given the size of the issue there, they would be a perfect test site > for this. OK, I will publish the code and the crash test tomorrow and then it can be reused I think for your real application. Best regards, Shamil -- Web: http://smsconsulting.spb.ru/shamil_s ----- Original Message ----- From: "John Colby" <jwcolby at ColbyConsulting.com> To: "'Access Developers discussion and problem solving'" <accessd at databaseadvisors.com> Sent: Monday, March 13, 2006 4:48 PM Subject: Re: [AccessD] Access XP forms bound to ADO recordsets > >Please do not spend a lot of time on it now or at least do not plan to > broadly use it > > I have one specific place that I want to use this, the form that is > causing > locking issues at Invo Health Care. Given the size of the issue there, > they > would be a perfect test site for this. > > > John W. Colby > www.ColbyConsulting.com > > > -----Original Message----- > From: accessd-bounces at databaseadvisors.com > [mailto:accessd-bounces at databaseadvisors.com] On Behalf Of Shamil > Salakhetdinov > Sent: Monday, March 13, 2006 3:20 AM > To: Access Developers discussion and problem solving > Subject: Re: [AccessD] Access XP forms bound to ADO recordsets > >> Does RecordsetClone become invalid? > No, it doesn't, John. > But it has another name. > Similar method for ADODB recordsets is called Clone. > >> I am looking at this now. > Please do not spend a lot of time on it now or at least do not plan to > broadly use it in your development until it's very well tested and its > limitations are clearly defined - there are rumors this feature introduce > instability in MS Access work. I have doubts in that because I haven't > seen > any time MS Access crashes when bound to disconnected ADODB recordsets the > way I described. > > On the other hand I did do "fight" in my work in the past with MS Access > GPFs, when listboxes/comboboxes were bound to ADODB recordsets but as far > as > I have found this wasn't the problem with ADODB recordsets but the problem > that in that case late bound DAO or ADODB recordets were used and these > latter were opened in library mdb and there was a bug when DAO recordsets > were used for ADP's forms and that was the cause of the floating GPF > trouble > or something like that. WIth this problem fixed the applications work now > well for more than a year. > > Shamil > > ----- Original Message ----- > From: "John Colby" <jwcolby at ColbyConsulting.com> > To: "'Access Developers discussion and problem solving'" > <accessd at databaseadvisors.com> > Sent: Monday, March 13, 2006 8:15 AM > Subject: Re: [AccessD] Access XP forms bound to ADO recordsets > > >> Shamil, >> >> I am looking at this now. Do you know if binding to an ADO recordset >> changes >> the data type of the RecordsetClone. I was under the impression that >> RecordsetClone was always a DAO recordset. Does RecordsetClone become >> invalid? I use RecordsetClone to perform many different operations, >> including syncing the form to a combo and VV. >> >> >> John W. Colby >> www.ColbyConsulting.com >> >> >> -----Original Message----- >> From: accessd-bounces at databaseadvisors.com >> [mailto:accessd-bounces at databaseadvisors.com] On Behalf Of Shamil >> Salakhetdinov >> Sent: Saturday, March 11, 2006 7:12 PM >> To: Access Developers discussion and problem solving >> Subject: Re: [AccessD] Access XP forms bound to ADO recordsets >> >> Dan, >> >> Yes, I have seen that - in fact I did do google before I started my >> experimenting. >> In KB281998 "How to bind Microsoft Access forms to ADO recordsets" >> http://support.microsoft.com/kb/281998 they talk AFAIS about binding to >> connected ADODB recordsets. >> >> The original question (as I got it) was hwo to bind to disconnected ADODB >> recordsets and then implied question is: is there a simple and generic >> way >> to translate/transfer changes from disconnected recordset to the >> backend... >> >> As it happens there is a trick to do that described in my previous >> posting. >> >> I did do google now additionally and I did find that the similar trick is >> described already several years ago. They do it a little bit differently >> but >> the principle is the same - they write: >> >> <<< >> Now, the clever tricks: >> >> 1. Open a static, optimistic batch recordset, disconnect it, save it to >> a >> simple in-memory stream object, set the stream position to zero so it can >> be >> read from the beginning, and open a new copy of the recordset from the >> stream. Now, bind one copy to the form, and start working. When you're >> ready to do a batch update, first compare the 2 recordsets for changes, >> and >> apply any adds, changes, and deletes to the unbound recordset, then run >> BatchUpdate from the unbound recordset. Note that Access sets values of >> IDENTITY columns to zero, so that's an easy way to filter for added >> records. >> ... >>>>> >> >> This excerpt is from this posting (watch line wraps!): >> >> <<< >> ADP: A2K vs 2002? >> From: Steve Jorgensen >> Date: Sun, Jul 21 2002 7:29 pm >> >> > http://groups.google.com/group/comp.databases.ms-access/browse_frm/thread/17 >> > 53dbca8189eb3/f20d79536029060e?hl=en&lr=&ie=UTF-8&oe=UTF-8&rnum=1&prev=/grou >> > ps%3Fas_q%3DBind%2520form%2520to%2520disconnected%2520recordset%26safe%3Dima >> > ges%26ie%3DUTF-8%26oe%3DUTF-8%26as_ugroup%3D*.*access.*%26lr%3D%26hl%3Den#f2 >> 0d79536029060e >>>>> >> >> And here is another related information: >> >> <<< >> From: Steve Jorgensen >> Date: Thurs, Nov 28 2002 11:45 pm >> >> > http://groups.google.com/group/comp.databases.ms-access/msg/40e731c75071f8c9 >> > ?q=Bind+form+to+disconnected+recordset+group:*.*access.*&hl=en&lr=&ie=UTF-8& >> oe=UTF-8&rnum=2 >>>>> >> >> So they approve that my trick is legal and is a kind of "wheel >> reinwention" >> - the difference of my "wheel" is that I do trasnslate changes to the >> second >> disconected recordset when form events fire - the disadvantage of my >> method >> is that it needs more tricky coding, which still needs to be well tested, >> the advantage - is that as soons as the changes on the current row are >> done >> I can serialize second disconnected recordset to xml file and in the case >> of >> client app's failure batch changes will not be lost etc. >> >> Strange that such a valuable information first time published in summer >> 2002 >> about using ADODB disconnected recordsets is so rarely discussed on >> Internet >> - everybody in this World is abandoning "MS Access toy" and switiching to >> .NET development? >> >> But this feature properly applied makes MS Access FEs good candidates to >> be >> used as true FEs - without any significant performance/locking hits on >> BEs > >> I >> mean.... >> >> Shamil >> >> ----- Original Message ----- >> From: "Dan Waters" <dwaters at usinternet.com> >> To: "'Access Developers discussion and problem solving'" >> <accessd at databaseadvisors.com> >> Sent: Sunday, March 12, 2006 2:27 AM >> Subject: Re: [AccessD] Access XP forms bound to ADO recordsets >> >> >>> Shamil, >>> >>> I've been reading you post with interest. Have you looked at MS KB >>> 281998? >>> This gives a method for an Access form to connect to SQL Server, Jet, >>> and >>> Oracle BE's and be updateable. They identify a specific provider to do >>> this >>> that can be used to set up bound forms. >>> >>> The provider is: "Microsoft.Access.OLEDB.10.0" >>> >>> I have not tried this, but thought you might be interested. >>> >>> Dan Waters >>> >>> >>> -----Original Message----- >>> From: accessd-bounces at databaseadvisors.com >>> [mailto:accessd-bounces at databaseadvisors.com] On Behalf Of Shamil >>> Salakhetdinov >>> Sent: Saturday, March 11, 2006 5:04 PM >>> To: Access Developers discussion and problem solving >>> Subject: Re: [AccessD] Access XP forms bound to ADO recordsets >>> >>> John at all, >>> >>> I did make some more experimenting and it happens that MS Access 2003 >>> (and >>> probably XP) and ADO 2.8 (and 2.7 also?) can work in bound mode with >>> disconnected updatable ADODB recordsets with both MS Access and MS SQL >>> backends. >>> >>> I did use Provider=Microsoft.Jet.OLEDB.4.0 to connect to MS Access >>> backend >>> and Provider=SQLOLEDB.1 to connect to MS SQL 2000 backend. >>> >>> Some more testing/experimenting is needed but I did do quite some tests >>> and >>> they worked OK. >>> >>> As I wrote already this feature is new for me and a (big) surprise - >>> this >>> is >>> a functionality I have been waiting for 8+ years since 1997 when we made >>> here a custom framework to work with MS Access and MS SQL in >>> disconnected >>> mode, but it was rather heavyweight and because of the bugs in MS Access >>> I >>> decided to not make it broadly available.... >>> >>> Basically this means that MS Access forms can be used in bound mode with >>> very low performance hit to the MS Access and MS SQL backends - the same >>> way >>> ADODB disconnected recordsets are used in n-tier applications. >>> >>> The programming of form's events processing is relatively simple and it >>> should be possible to generalize it to make a simple lightweight >>> framework >>> in case back-end database(s) follow systematic naming conventions and >>> database models design principles. >>> >>> The "trick" is to open two ADODB recordsets: >>> >>> - one with batch update enabled >>> - second without batch update >>> >>> and make them disconnected. >>> >>> Then bind MS Access form to the second recordset (without batch update >>> enabled). >>> >>> (I did experiemnet with recordsets having several source rows as a >>> generic >>> case to see are there any chances to use MS Access subforms in bound >>> editable mode with disconnected ADODB recordsets) >>> >>> When MS Access form fires insert, update, delete events all the changes >>> can >>> be easily translated from the second recordset (where these changes are >>> made >>> "automagically" because MS Access form is bound to it) to the first >>> recordset. >>> >>> On form close(or using special button) first recordset can be >>> reconnected >>> to >>> the backend and batch update applied. (Of course in the case of special >>> button to apply batch changes the two disconnected recordsets have to be >>> resynchronized after updates). >>> >>> etc. >>> >>> Here is how "automagically" generated by ADODB batch update looks in the >>> case of MS SQL backend (Info obtained from MS SQL profiler, line breaks >>> are >>> inserted manually to make it readable): >>> >>> exec sp_executesql >>> >>> N'UPDATE "Northwind".."Categories" SET >>> "CategoryID"=@P1,"CategoryName"=@P2,"Description"=@P3 WHERE >>> "CategoryID"=@P4 >>> AND "CategoryName"=@P5; >>> >>> DELETE FROM "Northwind".."Categories" WHERE "CategoryID"=@P6 AND >>> "CategoryName"=@P7; >>> >>> UPDATE "Northwind".."Categories" SET >>> "CategoryID"=@P8,"CategoryName"=@P9,"Description"=@P10 WHERE >>> "CategoryID"=@P11 AND "CategoryName"=@P12; >>> >>> INSERT INTO "Northwind".."Categories" >>> ("CategoryID","CategoryName","Description") VALUES (@P13, at P14, at P15)', >>> >>> N'@P1 int, at P2 nvarchar(15), at P3 ntext, at P4 int, at P5 nvarchar(15), at P6 >>> int, at P7 >>> nvarchar(15), at P8 int, at P9 nvarchar(15), at P10 ntext, at P11 int, at P12 >>> nvarchar(15), at P13 int, at P14 nvarchar(15), at P15 ntext', >>> >>> 99, N'CatName', N'Updated category description', >>> 99, N'CatName', >>> 66, N'DelCatName', >>> 991, N'CatName2N', N'Updated dscr', 991, N'CatName2', >>> 662, N'newCatName', N'new Cat description' >>> >>> Live connection to the back-end is needed only on opening of the source >>> recordsets and on applying batch changes. Therefore connections can be >>> pooled/should be possible to pool (I didn't experiment here) and to >>> share >>> them between several (many) front-end applications/clients if these >>> connections are opened using ActiveX DCOM servers running on server >>> PCs/.NET >>> Remoting(?) objects. As well as actual disconnected recordset creation >>> and >>> reconnection and backend update can be executed on (Web) server side - >>> depending on whatever is used on backend.... >>> >>> Yes, I know dynamic SPs accessing database tables directly do not look >>> nice >>> but there could be many ways to make it working differently using >>> predefined >>> stored procedures (e.g. by serializing ADODB recordset into XML file(s) >>> where all the updates (inserts, deletes, updates) are coded special >>> easily >>> parsed way and then reformat these XML files into the calls to the >>> predefined stored procedures etc.etc. >>> >>> Here is how it looks this saved XML(no direct correspondence with >>> presented >>> above batch T-SQL update) : >>> >>> - <xml xmlns:s="uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882" >>> xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882" >>> xmlns:rs="urn:schemas-microsoft-com:rowset" xmlns:z="#RowsetSchema"> >>> - <s:Schema id="RowsetSchema"> >>> - <s:ElementType name="row" content="eltOnly" rs:updatable="true"> >>> - <s:AttributeType name="CategoryID" rs:number="1" >>> rs:writeunknown="true" >>> rs:basecatalog="Northwind" rs:basetable="Categories1" >>> rs:basecolumn="CategoryID"> >>> <s:datatype dt:type="int" dt:maxLength="4" rs:precision="10" >>> rs:fixedlength="true" rs:maybenull="false" /> >>> </s:AttributeType> >>> - <s:AttributeType name="CategoryName" rs:number="2" >>> rs:writeunknown="true" >>> rs:basecatalog="Northwind" rs:basetable="Categories1" >>> rs:basecolumn="CategoryName"> >>> <s:datatype dt:type="string" dt:maxLength="15" rs:maybenull="false" /> >>> </s:AttributeType> >>> - <s:AttributeType name="Description" rs:number="3" rs:nullable="true" >>> rs:writeunknown="true" rs:basecatalog="Northwind" >>> rs:basetable="Categories1" >>> rs:basecolumn="Description"> >>> <s:datatype dt:type="string" dt:maxLength="1073741823" rs:long="true" >>> /> >>> </s:AttributeType> >>> <s:extends type="rs:rowbase" /> >>> </s:ElementType> >>> </s:Schema> >>> - <rs:data> >>> <z:row CategoryID="1" CategoryName="Beverages" Description="Soft >>> drinks, >>> coffees, teas, beers, and ales" /> >>> <z:row CategoryID="2" CategoryName="Condiments" Description="Sweet and >>> savory sauces, relishes, spreads, and seasonings" /> >>> <z:row CategoryID="3" CategoryName="Confections" Description="Desserts, >>> candies, and sweet breads" /> >>> <z:row CategoryID="4" CategoryName="Dairy Products" >>> Description="Cheeses" >>> /> >>> <z:row CategoryID="5" CategoryName="Grains/Cereals" >>> Description="Breads, >>> crackers, pasta, and cereal" /> >>> <z:row CategoryID="6" CategoryName="Meat/Poultry" Description="Prepared >>> meats" /> >>> <z:row CategoryID="7" CategoryName="Produce" Description="Dried fruit >>> and >>> bean curd" /> >>> <z:row CategoryID="8" CategoryName="Seafood" Description="Seaweed and >>> fish" /> >>> - <rs:update> >>> - <rs:original> >>> <z:row CategoryID="99" CategoryName="Update me" Description="Update >>> me - >>> OK" /> >>> </rs:original> >>> <z:row CategoryID="99" CategoryName="Update me" Description="Update >>> me - >>> OK1" /> >>> </rs:update> >>> - <rs:update> >>> - <rs:original> >>> <z:row CategoryID="991" CategoryName="Update me2" Description="Update >>> me2 - OK" /> >>> </rs:original> >>> <z:row CategoryID="991" CategoryName="Update me2" Description="Update >>> me2 - OK1" /> >>> </rs:update> >>> <z:row CategoryID="661" CategoryName="Inserted2" >>> Description="Inserted2" >>> /> >>> - <rs:insert> >>> <z:row CategoryID="662" CategoryName="Inserted3" Description="inserted >>> 3" >>> /> >>> </rs:insert> >>> - <rs:delete> >>> <z:row CategoryID="66" CategoryName="DeleteMe" Description="Deleted" /> >>> </rs:delete> >>> </rs:data> >>> </xml> >>> >>> I do not post code here now because I wanted to experiment more and >>> because >>> it would be useful if somebody else tries to repeat the "trick" >>> described >>> above - if it will work for them then a whole set of new opportunities >>> to >>> use MS Access as a real development tool will be opened.... >>> >>> I will post code after additional tests within one-two weeks when it >>> will >>> become clear that it works. >>> >>> Please post any links here if you think that my posted information looks >>> like "wheel reinvention" or you think it doesn't have practical >>> application >>> because of this or that several limitations etc.etc. >>> >>> Thank you. >>> >>> Shamil >>> >>> P.S. I have installed on my PC: >>> >>> - MS Windows 2003 Server SP1 >>> - MS Office 2003/MS Access 2003 SP1 >>> - MS SQL 2000 SP3a >>> - MDAC 2.8 >>> - NET Framework 1.1 and 2.0 >>> - Visual Studio 2003 and 2005 >>> - I have also MS SQL Server 2005 Express edition but I didn't experiment >>> with it >>> >>> P. P.S. Yes, I didn't talk about identity(autonumber) fields - I >>> generally >>> use GUIDs for PKs. >>> To properly manage numeric identity values some more tricks are needed - >>> I'd >>> be grateful if somebody post information on this subject >>> (updategram/diffgram XML is a direct solution here probably - and >>> serialized/saved ADODB batch update can be converted into diffgrams by >>> using >>> XSLT or VB(A) or VB.NET/C#/C++ code etc.) >>> >> >> <<< tail skipped >>> >> >> -- >> AccessD mailing list >> AccessD at databaseadvisors.com >> http://databaseadvisors.com/mailman/listinfo/accessd >> Website: http://www.databaseadvisors.com >> >> -- >> AccessD mailing list >> AccessD at databaseadvisors.com >> http://databaseadvisors.com/mailman/listinfo/accessd >> Website: http://www.databaseadvisors.com > > -- > AccessD mailing list > AccessD at databaseadvisors.com > http://databaseadvisors.com/mailman/listinfo/accessd > Website: http://www.databaseadvisors.com > > -- > AccessD mailing list > AccessD at databaseadvisors.com > http://databaseadvisors.com/mailman/listinfo/accessd > Website: http://www.databaseadvisors.com -- AccessD mailing list AccessD at databaseadvisors.com http://databaseadvisors.com/mailman/listinfo/accessd Website: http://www.databaseadvisors.com