using System; using System.Collections; using System.Collections.Generic; using System.Data; using System.Linq; using System.Text; using System.Threading; using umbraco.interfaces; namespace Umbraco.Core { /// /// Static and extension methods for the DataTable object /// internal static class DataTableExtensions { private static readonly Hashtable AliasToNames = new Hashtable(); private static readonly ReaderWriterLockSlim Lock = new ReaderWriterLockSlim(); /// /// Creates a DataTable with the specified alias and columns and uses a callback to populate the headers. /// /// /// /// /// /// /// This has been migrated from the Node class and uses proper locking now. It is now used by the Node class and the /// DynamicDocument extensions for legacy reasons. /// public static DataTable GenerateDataTable( string alias, Func>> getHeaders, Func>, IEnumerable>>>> rowData) { var dt = new DataTable(alias); //get the standard column headers from the standard data (not user data) var tableData = rowData(); var standardColHeaders = tableData.SelectMany(x => x.Item1).Select(x => x.Key).Distinct(); var userPropColHeaders = new List(); // get user property column headers var propertyHeaders = GetPropertyHeaders(alias, getHeaders); var ide = propertyHeaders.GetEnumerator(); while (ide.MoveNext()) { userPropColHeaders.Add(ide.Value.ToString()); } //now add all the columns, standard val headers first, then user val headers foreach (var dc in standardColHeaders.Union(userPropColHeaders).Select(c => new DataColumn(c))) { dt.Columns.Add(dc); } //add row data foreach(var r in rowData()) { dt.PopulateRow( (Hashtable)AliasToNames[alias], r.Item1, r.Item2); } return dt; } /// /// Helper method to return this ugly object /// /// /// /// This is for legacy code, I didn't want to go creating custom classes for these /// internal static List>, IEnumerable>>> CreateTableData() { return new List>, IEnumerable>>>(); } /// /// Helper method to deal with these ugly objects /// /// /// /// /// /// This is for legacy code, I didn't want to go creating custom classes for these /// internal static void AddRowData( List>, IEnumerable>>> rowData, IEnumerable> standardVals, IEnumerable> userVals) { rowData.Add(new System.Tuple>, IEnumerable>>( standardVals, userVals )); } private static Hashtable GetPropertyHeaders(string alias, Func>> getHeaders) { using (var l = new UpgradeableReadLock(Lock)) { if (AliasToNames.ContainsKey(alias)) return (Hashtable)AliasToNames[alias]; l.UpgradeToWriteLock(); var headers = getHeaders(alias); var def = new Hashtable(); foreach (var pt in headers) def.Add(pt.Key, pt.Value); AliasToNames.Add(alias, def); return def; } } private static void PopulateRow( this DataTable dt, IDictionary aliasesToNames, IEnumerable> standardVals, IEnumerable> userPropertyVals) { var dr = dt.NewRow(); foreach (var r in standardVals) { dr[r.Key] = r.Value; } foreach (var p in userPropertyVals.Where(p => p.Value != null)) { dr[aliasesToNames[p.Key].ToString()] = p.Value; } dt.Rows.Add(dr); } } }