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.

Reply via email to