Something I have been asked a lot lately is how to persist items from a xml repeating group into some database.
Although this focuses around persisting data in a repeating group stored in an InfoPath form. The concepts can be applied to generic xml. There is 2 ways to actually do this the one is use smartobject integration. Which has its own set of quirks. This post will deal with persisting data in the K2 workflow I will do a post later that will use integrated smartobjects for this.
First we should set up an InfoPath main datasource with a repeating group that we’re going to persist:
Lay out the workflow as the image below the first event in the only activity is a Server Event (code). The second event is a SmartObject event that we will use to persist the data.
The approach I’m going to take is going to leverage the destination rule functionality more importantly the use of advanced destination rules. I will post something on advanced destination rules shortly as I believe a lot of people out there aren’t aware of this functionality. However for the purposes of this post I’ve recorded a short video. Accessing advanced destination rules is done by navigating to the destination rule wizard and then clicking the back button as in the following video : Advanced Destination Rule.
The video shows us how to access the advanced destination rules, and how to create slots based on the number of items that have been created in the InfoPath repeating group. The important thing to note is that the value of the item instance in the group is then stored in the activity instance data, by ensuring that the at least one item within the repeating group is unique we can use it to identify a given row within the xml. The snippet below shows us how to access the xml field and perform an xpath query on the InfoPath xml that will allow us to retrieve the current row.
// Load the XMl from the XML field into xml document XmlDocument xmlDocument = new XmlDocument(); xmlDocument.LoadXml( K2.ProcessInstance.XmlFields["RepeatingList"].Value ); // Access the instance data at this point // this is the unique identifier we used to create the slots. string instanceData = K2.ActivityInstanceDestination.InstanceData.ToString(); XmlNode xmlNode = null; // Retrieve the my prefix namespace. XmlNamespaceManager nsm = new XmlNamespaceManager(xmlDocument.NameTable); nsm.AddNamespace( "my", xmlDocument.DocumentElement.GetNamespaceOfPrefix("my") ); // use XPath to identify the node we're looking for. XmlNode node = xmlDocument.SelectSingleNode( string.Format( "/my:myFields/my:InvoiceLineItem[my:UniqueLineId={0}]", instanceData ), nsm ); // Set the various activity level datafields which // will map up to the relevant values in the InfoPath form. // Note that they datafields need to be defined first. // The lines below don't actually create the datafields. K2.ActivityInstanceDestination.DataFields["LineId"].Value = node["my:UniqueLineId"].InnerText; K2.ActivityInstanceDestination.DataFields["Description"].Value = node["my:Description"].InnerText; K2.ActivityInstanceDestination.DataFields["Value"].Value = node["my:Value"].InnerText;
Finally we use a create type method on a smartobject to persist the data to a repository. In this post we simply used a SmartBox smartobject.
The smartobject event we placed in the workflow will persist the data to the correct repository. The smartobject event is configured as follows:
Finally the step most people ( including myself ) miss, setting up a suceeding rule. Basically we check whether all of the activity instance status values are set to completed. This will prevent the workflow from completing until all of the repeating items are persisted to the repository.
That’s all folks. Thanks for reading :).