Migrated logic to create a DataTable from a Node or pretty much any other object in to a central place so we only have to maintain code in one place.
Now need to just test it with Node and create the DynamicNode extension methods for returning as a DataTable.
This commit is contained in:
143
src/Umbraco.Core/DataTableExtensions.cs
Normal file
143
src/Umbraco.Core/DataTableExtensions.cs
Normal file
@@ -0,0 +1,143 @@
|
||||
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
|
||||
{
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Static and extension methods for the DataTable object
|
||||
/// </summary>
|
||||
internal static class DataTableExtensions
|
||||
{
|
||||
|
||||
private static readonly Hashtable AliasToNames = new Hashtable();
|
||||
private static readonly ReaderWriterLockSlim Lock = new ReaderWriterLockSlim();
|
||||
|
||||
/// <summary>
|
||||
/// Creates a DataTable with the specified alias and columns and uses a callback to populate the headers.
|
||||
/// </summary>
|
||||
/// <param name="alias"></param>
|
||||
/// <param name="getHeaders"></param>
|
||||
/// <param name="rowData"> </param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// 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.
|
||||
/// </remarks>
|
||||
public static DataTable GenerateDataTable(
|
||||
string alias,
|
||||
Func<string, IEnumerable<KeyValuePair<string, string>>> getHeaders,
|
||||
Func<IEnumerable<Tuple<IEnumerable<KeyValuePair<string, object>>, IEnumerable<KeyValuePair<string, object>>>>> 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<string>();
|
||||
// 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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to return this ugly object
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// This is for legacy code, I didn't want to go creating custom classes for these
|
||||
/// </remarks>
|
||||
internal static List<System.Tuple<IEnumerable<KeyValuePair<string, object>>, IEnumerable<KeyValuePair<string, object>>>> CreateTableData()
|
||||
{
|
||||
return new List<System.Tuple<IEnumerable<KeyValuePair<string, object>>, IEnumerable<KeyValuePair<string, object>>>>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to deal with these ugly objects
|
||||
/// </summary>
|
||||
/// <param name="rowData"></param>
|
||||
/// <param name="standardVals"></param>
|
||||
/// <param name="userVals"></param>
|
||||
/// <remarks>
|
||||
/// This is for legacy code, I didn't want to go creating custom classes for these
|
||||
/// </remarks>
|
||||
internal static void AddRowData(
|
||||
List<System.Tuple<IEnumerable<KeyValuePair<string, object>>, IEnumerable<KeyValuePair<string, object>>>> rowData,
|
||||
IEnumerable<KeyValuePair<string, object>> standardVals,
|
||||
IEnumerable<KeyValuePair<string, object>> userVals)
|
||||
{
|
||||
rowData.Add(new System.Tuple<IEnumerable<KeyValuePair<string, object>>, IEnumerable<KeyValuePair<string, object>>>(
|
||||
standardVals,
|
||||
userVals
|
||||
));
|
||||
}
|
||||
|
||||
private static Hashtable GetPropertyHeaders(string alias, Func<string, IEnumerable<KeyValuePair<string, string>>> 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<KeyValuePair<string, object>> standardVals,
|
||||
IEnumerable<KeyValuePair<string, object>> 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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -56,6 +56,7 @@
|
||||
<Compile Include="Configuration\FileSystemProviderElementCollection.cs" />
|
||||
<Compile Include="Configuration\FileSystemProvidersSection.cs" />
|
||||
<Compile Include="CoreBootManager.cs" />
|
||||
<Compile Include="DataTableExtensions.cs" />
|
||||
<Compile Include="DictionaryExtensions.cs" />
|
||||
<Compile Include="Dictionary\CultureDictionaryFactoryResolver.cs" />
|
||||
<Compile Include="Dictionary\ICultureDictionaryFactory.cs" />
|
||||
|
||||
@@ -9,6 +9,7 @@ using System.Xml.XPath;
|
||||
using umbraco.cms.businesslogic;
|
||||
using umbraco.cms.businesslogic.propertytype;
|
||||
using umbraco.interfaces;
|
||||
using Umbraco.Core;
|
||||
|
||||
namespace umbraco.NodeFactory
|
||||
{
|
||||
@@ -358,30 +359,11 @@ namespace umbraco.NodeFactory
|
||||
|
||||
public DataTable ChildrenAsTable()
|
||||
{
|
||||
if (Children.Count > 0)
|
||||
{
|
||||
DataTable dt = generateDataTable(Children[0]);
|
||||
|
||||
string firstNodeTypeAlias = Children[0].NodeTypeAlias;
|
||||
|
||||
foreach (Node n in Children)
|
||||
{
|
||||
if (n.NodeTypeAlias == firstNodeTypeAlias)
|
||||
{
|
||||
DataRow dr = dt.NewRow();
|
||||
populateRow(ref dr, n, getPropertyHeaders(n));
|
||||
dt.Rows.Add(dr);
|
||||
}
|
||||
}
|
||||
return dt;
|
||||
}
|
||||
else
|
||||
return new DataTable();
|
||||
return Children.Count > 0 ? GenerateDataTable(Children[0]) : new DataTable();
|
||||
}
|
||||
|
||||
public DataTable ChildrenAsTable(string nodeTypeAliasFilter)
|
||||
{
|
||||
|
||||
if (Children.Count > 0)
|
||||
{
|
||||
|
||||
@@ -399,94 +381,58 @@ namespace umbraco.NodeFactory
|
||||
|
||||
if (nodeFound)
|
||||
{
|
||||
DataTable dt = generateDataTable(Firstnode);
|
||||
|
||||
foreach (Node n in Children)
|
||||
{
|
||||
if (n.NodeTypeAlias == nodeTypeAliasFilter)
|
||||
{
|
||||
DataRow dr = dt.NewRow();
|
||||
populateRow(ref dr, n, getPropertyHeaders(n));
|
||||
dt.Rows.Add(dr);
|
||||
}
|
||||
}
|
||||
return dt;
|
||||
return GenerateDataTable(Firstnode);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new DataTable();
|
||||
}
|
||||
}
|
||||
else
|
||||
return new DataTable();
|
||||
}
|
||||
return new DataTable();
|
||||
}
|
||||
|
||||
private DataTable generateDataTable(Node SchemaNode)
|
||||
private DataTable GenerateDataTable(INode node)
|
||||
{
|
||||
DataTable NodeAsDataTable = new DataTable(SchemaNode.NodeTypeAlias);
|
||||
string[] defaultColumns = {
|
||||
"Id", "NodeName", "NodeTypeAlias", "CreateDate", "UpdateDate", "CreatorName",
|
||||
"WriterName", "Url"
|
||||
};
|
||||
foreach (string s in defaultColumns)
|
||||
{
|
||||
DataColumn dc = new DataColumn(s);
|
||||
NodeAsDataTable.Columns.Add(dc);
|
||||
}
|
||||
|
||||
// add properties
|
||||
Hashtable propertyHeaders = getPropertyHeaders(SchemaNode);
|
||||
IDictionaryEnumerator ide = propertyHeaders.GetEnumerator();
|
||||
while (ide.MoveNext())
|
||||
{
|
||||
DataColumn dc = new DataColumn(ide.Value.ToString());
|
||||
NodeAsDataTable.Columns.Add(dc);
|
||||
}
|
||||
|
||||
return NodeAsDataTable;
|
||||
//use new utility class to create table so that we don't have to maintain code in many places, just one
|
||||
var dt = Umbraco.Core.DataTableExtensions.GenerateDataTable(
|
||||
//pass in the alias
|
||||
node.NodeTypeAlias,
|
||||
//pass in the callback to extract the Dictionary<string, string> of user defined aliases to their names
|
||||
alias =>
|
||||
{
|
||||
var ct = ContentType.GetByAlias(alias);
|
||||
return ct.PropertyTypes.ToDictionary(x => x.Alias, x => x.Name);
|
||||
},
|
||||
//pass in a callback to populate the datatable, yup its a bit ugly but it's already legacy and we just want to maintain code in one place.
|
||||
() =>
|
||||
{
|
||||
//create all row data
|
||||
var tableData = Umbraco.Core.DataTableExtensions.CreateTableData();
|
||||
//loop through each child and create row data for it
|
||||
foreach (Node n in Children)
|
||||
{
|
||||
var standardVals = new Dictionary<string, object>()
|
||||
{
|
||||
{"Id", n.Id},
|
||||
{"NodeName", n.Name},
|
||||
{"NodeTypeAlias", n.NodeTypeAlias},
|
||||
{"CreateDate", n.CreateDate},
|
||||
{"UpdateDate", n.UpdateDate},
|
||||
{"CreatorName", n.CreatorName},
|
||||
{"WriterName", n.WriterName},
|
||||
{"Url", library.NiceUrl(n.Id)}
|
||||
};
|
||||
var userVals = new Dictionary<string, object>();
|
||||
foreach (var p in from Property p in n.Properties where p.Value != null select p)
|
||||
{
|
||||
userVals[p.Alias] = p.Value;
|
||||
}
|
||||
//add the row data
|
||||
Umbraco.Core.DataTableExtensions.AddRowData(tableData, standardVals, userVals);
|
||||
}
|
||||
return tableData;
|
||||
}
|
||||
);
|
||||
return dt;
|
||||
}
|
||||
|
||||
private Hashtable getPropertyHeaders(Node SchemaNode)
|
||||
{
|
||||
if (_aliasToNames.ContainsKey(SchemaNode.NodeTypeAlias))
|
||||
return (Hashtable)_aliasToNames[SchemaNode.NodeTypeAlias];
|
||||
else
|
||||
{
|
||||
ContentType ct = ContentType.GetByAlias(SchemaNode.NodeTypeAlias);
|
||||
Hashtable def = new Hashtable();
|
||||
foreach (PropertyType pt in ct.PropertyTypes)
|
||||
def.Add(pt.Alias, pt.Name);
|
||||
System.Web.HttpContext.Current.Application.Lock();
|
||||
_aliasToNames.Add(SchemaNode.NodeTypeAlias, def);
|
||||
System.Web.HttpContext.Current.Application.UnLock();
|
||||
|
||||
return def;
|
||||
}
|
||||
}
|
||||
|
||||
private void populateRow(ref DataRow dr, Node n, Hashtable AliasesToNames)
|
||||
{
|
||||
dr["Id"] = n.Id;
|
||||
dr["NodeName"] = n.Name;
|
||||
dr["NodeTypeAlias"] = n.NodeTypeAlias;
|
||||
dr["CreateDate"] = n.CreateDate;
|
||||
dr["UpdateDate"] = n.UpdateDate;
|
||||
dr["CreatorName"] = n.CreatorName;
|
||||
dr["WriterName"] = n.WriterName;
|
||||
dr["Url"] = library.NiceUrl(n.Id);
|
||||
|
||||
int counter = 8;
|
||||
foreach (Property p in n.Properties)
|
||||
{
|
||||
if (p.Value != null)
|
||||
{
|
||||
dr[AliasesToNames[p.Alias].ToString()] = p.Value;
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void initializeStructure()
|
||||
{
|
||||
// Load parent if it exists and is a node
|
||||
|
||||
@@ -22,15 +22,15 @@ namespace umbraco.MacroEngines.Library
|
||||
|
||||
internal static INode ConvertToNode(this DynamicDocument doc)
|
||||
{
|
||||
var node = new SimpleNode(doc);
|
||||
var node = new ConvertedNode(doc);
|
||||
return node;
|
||||
}
|
||||
|
||||
private class SimpleNode : INode
|
||||
private class ConvertedNode : INode
|
||||
{
|
||||
private readonly DynamicDocument _doc;
|
||||
|
||||
public SimpleNode(DynamicDocument doc)
|
||||
public ConvertedNode(DynamicDocument doc)
|
||||
{
|
||||
_doc = doc;
|
||||
template = doc.TemplateId;
|
||||
|
||||
Reference in New Issue
Block a user