Thank you for this infomration, I will take a day or two to read and understand. I appreciate your thoughts. Cheers Mark
-----Original Message----- From: Thomas Tomiczek [mailto:[EMAIL PROTECTED]] Sent: Thursday, 10 October 2002 12:34 AM To: [EMAIL PROTECTED] Subject: Re: [ADVANCED-DOTNET] Strongly-Typed DataSets vs. Strongly-Typed Collections OK, mark - this is very simple :-) Now, databinding is something we are still working on. Dont get it as a "non solvable" issue, but we have concentrated on what we need to get our own software working, and we have been very reluctant to use databinding anyways. There is a list already that will soon support the necessary interfaces, and we will implement into the "superclass" whatever is necessary for binding. Shame on MS for not supporting business object binding "more directly". Now, what we do is basically this: You define your data the way you are used to it - as objects. The objects carry all information for mapping them to a database, caching, field types - everything. Actually that much that very soon the database can be autogenerated :-) You make a query model built on objects. The objects actually have internally (transparent to the user -thats why the properties are abstract) a DataCOntainer that holds the current data, as well (!) as state flags. NO "oiginal data" etc. The objects are dynamically pushed into and out of thedatabase based on - well - a not too easy compiled schema model. Now, dont get "compiled" wrong here - the compilation takes place immediatly before the first use of the model at runtime right now, and is used to actually do things like determine in which order things have to be done. How do you use this? Well, here some code snippets from our CMS. VERY little code, but you get the idea.... This is SAMPLE CODE, stripped of certain checks or clarity... Thats how you can query the database for objects. We are expanding a tree in a treevie... // Thats the node that expands. There is checking code etc. removed. TreeNode tn = e.Node; // The node tag contains the "OLD" business object for the container (folder etc.) we want to expand. We need to get this into the current transaction. Container superc = (Container) ContentManager.EntityManager.ReEstablish ((Container) tn.Tag); // Lets query for subcontainers IN THE NON-OO WAY. There is a different way, but this here uses the simple query syntax. Query q = ContentManager.EntityManager.CreateQuery (typeof (Container), new Condition ("SuperContainerREF", Expression.Equals, superc.OID)); // We dont want just object primary keys - please get all fields immediatly. q.FullFetch = true; // Execute the query... QueryResults r = ContentManager.EntityManager.Find (q); foreach (Container c in r) { TreeNode tn2 = new TreeNode (); tn2.Tag = c; tn2.Text = c.FriendlyName; // Set the image idnex. NOW - we have an image for different SUBTYPES (!) of Container returned, which the broker decides dynamically // Every subtype CAN have additional fields from other tables. tn2.SelectedImageIndex = GetItemIndexFor (c, false); } Thats a simple insertion, actually, as a sample. Whenever (in this Content Management System we develop) you create a new site, it has to automatically create Sub-containers to hold templates, the content etc. This is done with a callback into the SiteContainer object. The SiteContainer looks like this. This is "most code" - I have just stripped attributes that basically to into Editor integration. // The Container supertye defines one field as a "TypeSelector" that is responsible for defining the subtype. It is a char(4). Thats our selection criteria // NOTE that this class has NO additional fields and / or mappings - it is there just to dtermine functionality [TypeSelection ("SITE")] // We are a subtype of Container. We represent a Website in the CMS. public abstract class SiteContainer : Container, IEntityObjectAction { // This callback is called after an object was created BEFORE the call returns to the program. // We need to create the predetermines subcontainers. These are three SystemFolderContainers with different names. void IEntityObjectAction.PostCreate () { SystemFolderContainer f1 = (SystemFolderContainer) EntityBroker.Create (typeof(SystemFolderContainer)); f1.FriendlyName = "#templates"; f1.SuperContainer = this; SystemFolderContainer f2 = (SystemFolderContainer) EntityBroker.Create (typeof(SystemFolderContainer)); f2.FriendlyName = "#bin"; f2.SuperContainer = this; SystemFolderContainer f3 = (SystemFolderContainer) EntityBroker.Create (typeof(SystemFolderContainer)); f3.FriendlyName = "#content"; f3.SuperContainer = this; } // Called before deletion, but we make nothing void IEntityObjectAction.PreDelete () { } } Lets see into the code for a name change on a container, again SAMPLE CODE LEVEL - no error handling etc. Thats the error handler of the TreeView AfterLabelEdit event... // Lets get the node and the related business object again... TreeNode tn = e.Node; Container c = (Container) tn.Tag; // Re reestablish it in the current transaction (actually getting new data from the database). c = (Container) ContentManager.EntityManager.ReEstablish (c); // Lets change the name c.FriendlyName = e.Label; // Commit the transaction (our app does not use distributed transactions here). ContentManager.EntityManager.CommitTransaction (); Lets do something more complicated. Lets load a directory into the CMS - last sample: This sample is loading a directory (recursive) into the CMS, into "SimpleFileContainers. In order to be faster and use less memory, we do commit after all files in a directory. Otherwise we would use possibly a LOT of memory. This is NOT done to handle extremely large files - it is meant for "regular website import". private void AddContent (Container SuperContainer, string[] content) { bool commit = true; ArrayList Dirs = new ArrayList(); SuperContainer = (Container) ContentManager.EntityManager.ReEstablish (SuperContainer); Guid SC_Oid = SuperContainer.OID; Container c2 = null; // add the objects foreach (string item in content) { try { string ext = Path.GetExtension (item); // if new container is a file if (!ext.Equals(String.Empty)) { // get the MIME type of the file MimeType mt = ContentManager.GetMimeTypeByExtension (ext.Substring (1)); // create new container to insert c2 = (FileContainer) ContentManager.EntityManager.Create (typeof(FileContainer)); c2.FriendlyName = Path.GetFileNameWithoutExtension(item); c2.SuperContainer = SuperContainer; // read in the file FileStream instream = new FileStream (item, FileMode.Open, FileAccess.Read, FileShare.Read); if (mt.IsBinary) { byte[] newdata = new byte[instream.Length]; instream.Read (newdata, 0, (int)instream.Length); c2.ParticleData = newdata; instream.Close(); } else { StreamReader sr = new StreamReader (instream); c2.ParticleText = sr.ReadToEnd(); sr.Close(); } // set the MIME type of the Container c2.Particle.MimeType = mt; } else { // create new container to insert c2 = (FolderContainer) ContentManager.EntityManager.Create (typeof(FolderContainer)); c2.FriendlyName = Path.GetFileNameWithoutExtension(item); c2.SuperContainer = SuperContainer; Dirs.Add (item); } } catch (Exception ex) { string message = String.Format("{0}: {1}\nDo you want to continue with drag and drop?", Path.GetFileName(item), ex.Message); DialogResult dr = MessageBox.Show (this, message, "Error", MessageBoxButtons.YesNo, MessageBoxIcon.Error); if (dr == DialogResult.No) { commit = false; break; } if (c2 != null) { ContentManager.EntityManager.Delete (c2); } } } if (commit) { ContentManager.EntityManager.CommitTransaction (); } Parameter QuerySuperContParam = new Parameter("SuperContainerID"); Parameter QueryFriendlyNameParam = new Parameter ("FriendlyName"); Query Q = ContentManager.EntityManager.CreateQuery (typeof (Container), new Condition ("SuperContainerREF", Expression.Equals, QuerySuperContParam), new Condition ("FriendlyName", Expression.Like, QueryFriendlyNameParam)); Q.FullFetch = true; foreach (string d in Dirs) { // search for the container object that respresents the directory QuerySuperContParam.Value = SC_Oid; QueryFriendlyNameParam.Value = Path.GetFileNameWithoutExtension (d); Container cont = (Container) ContentManager.EntityManager.FindScalar (Q); // add the content of the directory AddContent (cont, GetDirectoryContent(d)); } } SO, I hope that helps you guys out a little :-) BTW - for perofrmance reasons etc. the last example is doing some work under the scenes. c2.ParticleData and c2.ParticleData are actually shortcuts for going two level deep into storage hierarchy :-) Every container with "data" in it is actually three tables (with three objects). Thomas Tomiczek THONA Consulting Ltd. (Microsoft MVP C#/.NET) You can read messages from the Advanced DOTNET archive, unsubscribe from Advanced DOTNET, or subscribe to other DevelopMentor lists at http://discuss.develop.com. You can read messages from the Advanced DOTNET archive, unsubscribe from Advanced DOTNET, or subscribe to other DevelopMentor lists at http://discuss.develop.com.