private void WriteDirectValue(CommenceValue v) { _xw.WriteStartElement(XmlConvert.EncodeLocalName(base.ExportHeaders[v.ColumnDefinition.ColumnIndex])); // only write if we have something if (!string.IsNullOrEmpty(v.DirectFieldValue)) { // can we get away with writing the value or do we need to use CData? if (v.ColumnDefinition.CommenceFieldDefinition.MaxChars == CommenceLimits.MaxTextFieldCapacity) { _xw.WriteCData(v.DirectFieldValue); } else { _xw.WriteString(v.DirectFieldValue); } } _xw.WriteEndElement(); }
/// <summary> /// Takes raw cursor data and returns a list of CommenceValue lists /// </summary> /// <param name="rawdata">Data</param> /// <returns>A list of CommenceValue lists</returns> private List <List <CommenceValue> > ProcessDataBatch(string[][] rawdata) { List <List <CommenceValue> > retval = new List <List <CommenceValue> >(); CommenceValue cv; ColumnDefinition cd; // rawdata represents the actual database row values for (int i = 0; i < rawdata.GetLength(0); i++) // rows { List <CommenceValue> rowdata = new List <CommenceValue>(); // for thids we can assume the first row of rawdata contains the thid if (this.useThids) { cv = new CommenceValue(rawdata[i][0], this.columnDefinitions.First()); // assumes thid column is first. This is an accident waiting to happen. rowdata.Add(cv); } // process row for (int j = 1; j < rawdata[i].Length; j++) // columns { // a column for the thid is only returned when a thid is requested // therefore getting the right column is a little tricky int colindex; if (this.useThids) { colindex = j; } else { colindex = j - 1; } cd = this.columnDefinitions[colindex]; string[] buffer; if (cd.IsConnection) { if (string.IsNullOrEmpty(rawdata[i][j].Trim())) // should we trim? { cv = new CommenceValue(cd); // always create a CommenceValue for consistency } else { if (!settings.SplitConnectedItems) { buffer = new string[] { rawdata[i][j] }; // just return as-is cv = new CommenceValue(buffer, cd); } else { if (cd.Delimiter == "\n") { switch (cd.CommenceFieldDefinition.Type) { case CommenceFieldType.Text: case CommenceFieldType.URL: // any non-Name text field in Commence will accept a \n // we use a regex to split values at "\n" *but not* "\r\n" // this is not 100% fail-safe as a fieldvalue *can* contain just \n if it is a large text field. // in that case, your only option is to suppress the splitting in ExportSettings buffer = regex.Split(rawdata[i][j]); // this may result in Commence fieldvalues being split incorrectly if they contain embedded delimiters. break; default: buffer = rawdata[i][j].Split(new string[] { cd.Delimiter }, StringSplitOptions.None); break; } // switch } else { buffer = rawdata[i][j].Split(new string[] { cd.Delimiter }, StringSplitOptions.None); } // buffer now contains the connected values as array, do any formatting transformation buffer = FormatValues(buffer, cd); cv = new CommenceValue(buffer, cd); } } } // if IsConnection else //a direct value { buffer = new string[] { rawdata[i][j] }; buffer = FormatValues(buffer, cd); cv = new CommenceValue(buffer[0], cd); } rowdata.Add(cv); } // for j retval.Add(rowdata); } // for i return(retval); }
/// <summary> /// Reads data using DDE. This is extremely show and should only ever be used as a last resort. /// </summary> /// <param name="mocktables"></param> internal void GetDataByDDE(List <TableDef> mocktables) // needs fixing { /* DDE requests are limited to a maximum length of 255 characters, * which is easily exceeded. A workaround is splitting the requests. * Not pretty but the only way to get to many-many relationships that contain >93750 worth of connected characters * without setting the maxfieldsize higher. */ List <List <CommenceValue> > rows; List <CommenceValue> rowvalues; ICommenceDatabase db = new CommenceDatabase(); // always define a category db.ViewCategory(this.cursor.Category); // are we dealing with a view? if (!string.IsNullOrEmpty(cursor.View)) { db.ViewView(this.cursor.View); } int itemCount = db.ViewItemCount(); for (int i = 1; i <= itemCount; i++) // note that we use a 1-based iterator { rows = new List <List <CommenceValue> >(); rowvalues = new List <CommenceValue>(); foreach (TableDef td in mocktables) { string[] DDEResult = null; List <string> fieldNames = td.ColumnDefinitions.Select(o => o.FieldName).ToList(); if (td.Primary) { // ViewFields and ViewConnectedFields have a limited capacity // the total length of a DDE command cannot exceed 255 characters // What we are going to do is limit the number of characters to a value of up to 150 chars, // to be on the safe side (ViewConnectedFilter and two delimiters already make up 35 characters!) ListChopper lcu = new ListChopper(fieldNames, 150); foreach (List <string> l in lcu.Portions) { DDEResult = db.ViewFields(i, l); // we have our results, we now have to create CommenceValue objects from it // and we also have to match them up with their respective column // this is a little tricky... for (int j = 0; j < DDEResult.Length; j++) { ColumnDefinition cd = td.ColumnDefinitions.Find(o => o.FieldName.Equals(l[j])); string[] buffer = new string[] { DDEResult[j] }; //buffer = FormatValues(buffer,this.Formatting, cd); buffer = FormatValues(buffer, cd); CommenceValue v = new CommenceValue(buffer[0], cd); rowvalues.Add(v); } // for } // list l } else // we are dealing with a connection { int conItemCount = db.ViewConnectedCount(i, td.ColumnDefinitions[0].Connection, td.ColumnDefinitions[0].Category); // doesn't matter which one we use // here's a nice challenge: // upon every iteration we get a row of fieldvalues from the connection // to make things worse, we chop them up so it aren't even complete rows. // we must aggregate the values for each field. // We'll construct a datatable to hack around that; // we could have also used a dictionary I suppose. // using a datatable may be easiest DataTable dt = new DataTable(); for (int c = 0; c < fieldNames.Count; c++) { dt.Columns.Add(fieldNames[c]); // add fields as columns, keeping everything default } // loop all connected items for (int citemcount = 1; citemcount <= conItemCount; citemcount++) { DataRow dr = dt.NewRow(); // create a row containing all columns ListChopper lcu = new ListChopper(fieldNames, 150); foreach (List <string> list in lcu.Portions) { DDEResult = db.ViewConnectedFields(i, td.ColumnDefinitions[0].Connection, td.ColumnDefinitions[0].Category, citemcount, list); // populate colums for the fields we requested for (int j = 0; j < DDEResult.Length; j++) { dr[list[j]] = DDEResult[j]; } } // list l dt.Rows.Add(dr); } // citemcount // create a CommenceValue from every column in the datatable foreach (DataColumn dc in dt.Columns) { // this will also return columns that have no data, which is what we want. string[] query = (from r in dt.AsEnumerable() select r.Field <String>(dc.ColumnName)).ToArray(); ColumnDefinition cd = td.ColumnDefinitions.Find(o => o.FieldName.Equals(dc.ColumnName)); CommenceValue cv = null; if (query.Length > 0) // only create value if there is one { //query = FormatValues(query, this.Formatting, cd); query = FormatValues(query, cd); cv = new CommenceValue(query, cd); } else { // create empty CommenceValue cv = new CommenceValue(cd); } rowvalues.Add(cv); } } // if } // foreach tabledef rows.Add(rowvalues); CursorDataReadProgressChangedArgs args = new CursorDataReadProgressChangedArgs(rows, i, totalRows); // progress within the cursor OnDataProgressChanged(args); } // i db = null; ExportCompleteArgs a = new ExportCompleteArgs(itemCount); OnDataReadCompleted(a); }