Waiting to Inhale (Cont.) Secretary of RowState I have never been a big fan of transmitting DataSets via Web services because they tend to be pretty bloated. I prefer to send arrays of entity classes via .NET Remoting. However, I had a client recently that wanted to use the batch updating feature of DataSets on a PocketPC device using the .NET Compact Framework. For various reasons (most notably feature lock in, configuration, and security issues) they wanted to avoid using Remote Data Access (RDA) and Merge Replication to get data from their Web service (the .NET CF doesn't support Remoting) into SQL Server CE on a PDA. What I needed to do to get this process working optimally was change the RowState property of each DataRow object to DataRowState.Added inside the Web service before I sent it over the wire to the PocketPC device, so that all it had to do was use a SqlDataAdapter object and a SqlCommandBuilder object to batch insert the contents of the DataSet into SQL Server CE. Unfortunately, the RowState property of the DataRow class is read only, so I had to get a bit creative. I came up with two approaches that accomplish what I needed. The first was to serialize the DataSet to an XML string, manually insert the HasChanges="inserted" DiffGram hint using string manipulation, then deserialize the string back into a DataSet object: //...load DataSet into variable ?ds?...//
XmlSerializer serializer = new XmlSerializer(typeof(DataSet)); MemoryStream ms = new MemoryStream(); serializer.Serialize(ms,ds); string xml = Encoding.ASCII.GetString(ms.ToArray()); ms.Close(); xml = xml.Replace("<Table","<Table diffgr:hasChanges=\"inserted\""); ds = (DataSet)serializer.Deserialize(new MemoryStream(Encoding.ASCII.GetBytes(xml)));
The approach above worked relatively well, but since serialization requires Reflection, and a host of other "not so speedy" processes, I sought out a faster solution that was less of a "hack." The approach below is nearly three times as fast as the serialization example: //...load DataSet into variable ?ds?...//
ds2 = ds.Clone();
for(int i=0;i<ds.Tables[0].Rows.Count;i++) { ds2.Tables[0].Rows.Add( ds.Tables[0].Rows[i].ItemArray); }
Note that you need to clone the source DataSet in order to preserve its schema, which will enable the batch update process on the PocketPC device to work properly. You then loop through the source DataSet and copy each row to the target DataSet. This adds the "inserted" hint to the DiffGram for each row. You have to use the ItemArray property of each DataRow object, because a DataRow reference cannot be assigned to more than one DataTable (it generates an exception). Sadly, the RowState property of the DataRow class is still read only in the .NET Framework v2.0. I'll request the change, though, and perhaps the Microsoft machine will respond favorably. Until next issue, stay angry and don't follow the rules that suck. My name is Jonathan Goodyear and I am the angryCoder. Jonathan D Goodyear |