// Spludlow Software // Copyright © Samuel P. Ludlow 2020 All Rights Reserved // Distributed under the terms of the GNU General Public License version 3 // Distributed WITHOUT ANY WARRANTY; without implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE // https://www.spludlow.co.uk/LICENCE.TXT // The Spludlow logo is a registered trademark of Samuel P. Ludlow and may not be used without permission // v1.14 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Data; using System.Reflection; namespace Spludlow.Data { public class ADO { public static string TruncateMaxStrings(DataRow row) { StringBuilder report = null; foreach (DataColumn dataColumn in row.Table.Columns) { if (dataColumn.DataType != typeof(string)) continue; if (row.IsNull(dataColumn) == true) continue; string data = (string)row[dataColumn]; if (data.Length <= dataColumn.MaxLength) continue; row[dataColumn] = data.Substring(0, dataColumn.MaxLength); if (report == null) report = new StringBuilder(); report.Append(row.Table.TableName); report.Append("."); report.Append(dataColumn.ColumnName); report.Append("\t"); report.Append(dataColumn.MaxLength); report.Append("\t"); report.Append(data.Length); report.AppendLine(); } if (report == null) return null; return report.ToString(); } public static string ValidateStringLengths(DataRow row) // Code dup above { StringBuilder text = new StringBuilder(); foreach (DataColumn dataColumn in row.Table.Columns) { if (dataColumn.DataType != typeof(string)) continue; if (row.IsNull(dataColumn) == true) continue; string data = (string)row[dataColumn]; if (data.Length > dataColumn.MaxLength) { Spludlow.Log.Warning("ValidateStringLengths: " + row.Table.TableName + "." + dataColumn.ColumnName, data); if (text.Length > 0) text.Append(", "); text.Append(dataColumn.ColumnName); text.Append(":"); text.Append(data.Length); text.Append("/"); text.Append(dataColumn.MaxLength); //row[dataColumn] = data.Substring(0, dataColumn.MaxLength); } } if (text.Length == 0) return ""; text.Insert(0, "Text is too long, shorten it; "); return text.ToString(); } public static DataTable Swivel(DataRow row) { return Swivel(row, null); } public static DataTable Swivel(DataTable table) { return Swivel(new DataView(table), null); } public static DataTable Swivel(DataView view) { return Swivel(view, null); } public static DataTable Swivel(DataRow row, string[] columnNames) { DataTable table = row.Table.Clone(); table.ImportRow(row); return Swivel(new DataView(table), columnNames); } public static DataTable Swivel(DataTable table, string[] columnNames) { return Swivel(new DataView(table), columnNames); } public static DataTable Swivel(DataView view, string[] columnNames) { List columnNameList = null; if (columnNames != null) columnNameList = new List(columnNames); DataTable resultTable = new DataTable(view.Table.TableName); resultTable.Columns.Add("Name", typeof(string)); for (int rowIndex = 0; rowIndex < view.Count; ++rowIndex) resultTable.Columns.Add("Column" + rowIndex, typeof(string)); foreach (DataColumn column in view.Table.Columns) { if (columnNameList != null && columnNameList.Contains(column.ColumnName) == false) continue; DataRow resultRow = resultTable.NewRow(); resultRow[0] = column.ColumnName; for (int rowIndex = 0; rowIndex < view.Count; ++rowIndex) { if (column.DataType.Name != "String") resultRow[rowIndex + 1] = Spludlow.SimpleEncoding.Encode(view[rowIndex].Row[column], column.DataType.Name); else resultRow[rowIndex + 1] = view[rowIndex].Row[column]; } resultTable.Rows.Add(resultRow); } return resultTable; } public static DataSet WireDataSetObject(object data) { Type type = data.GetType(); if (typeof(DataSet).IsAssignableFrom(type) == true) return (DataSet)data; if (typeof(DataRow).IsAssignableFrom(type) == true) return WireDataSet((DataRow)data); if (typeof(DataRow[]).IsAssignableFrom(type) == true) return WireDataSet((DataRow[])data); if (typeof(DataRow[][]).IsAssignableFrom(type) == true) return WireDataSet((DataRow[][])data); if (typeof(DataView).IsAssignableFrom(type) == true) return WireDataSet((DataView)data); if (typeof(DataView[]).IsAssignableFrom(type) == true) return WireDataSet((DataView[])data); if (typeof(DataTable).IsAssignableFrom(type) == true) return WireDataSet((DataTable)data); if (typeof(DataTable[]).IsAssignableFrom(type) == true) return WireDataSet((DataTable[])data); return null; } public static DataSet WireDataSet(DataRow row) { DataTable table = row.Table.Clone(); table.ImportRow(row); DataSet dataSet = new DataSet(); dataSet.Tables.Add(table); return dataSet; } public static DataSet WireDataSet(DataRow[] rows) { DataSet dataSet = new DataSet(); if (rows.Length > 0) { DataTable table = rows[0].Table.Clone(); foreach (DataRow row in rows) table.ImportRow(row); dataSet.Tables.Add(table); } return dataSet; } public static DataSet WireDataSet(DataRow[][] arrayOfrows) { DataSet dataSet = new DataSet(); foreach (DataRow[] rows in arrayOfrows) { if (rows.Length > 0) { DataTable table = rows[0].Table.Clone(); foreach (DataRow row in rows) table.ImportRow(row); dataSet.Tables.Add(table); } } return dataSet; } public static DataSet WireDataSet(DataView view) { DataSet dataSet = new DataSet(); DataTable table = view.Table.Clone(); foreach (DataRowView rowView in view) table.ImportRow(rowView.Row); dataSet.Tables.Add(table); return dataSet; } public static DataSet WireDataSet(DataView[] views) { DataSet dataSet = new DataSet(); foreach (DataView view in views) { DataTable table = view.Table.Clone(); foreach (DataRowView rowView in view) table.ImportRow(rowView.Row); dataSet.Tables.Add(table); } return dataSet; } public static DataSet WireDataSet(DataTable table) { if (table.DataSet != null && table.DataSet.Tables.Count == 1) return table.DataSet; DataSet dataSet = new DataSet(); dataSet.Tables.Add(table.Copy()); //if (table.DataSet != null) // dataSet.Tables.Add(table.Copy()); //else // dataSet.Tables.Add(table); return dataSet; } public static DataSet WireDataSet(DataTable[] tables) { DataSet dataSet = new DataSet(); foreach (DataTable table in tables) { string tableName = table.TableName; while (dataSet.Tables.Contains(tableName) == true) // Bodge for now tableName += "0"; table.TableName = tableName; if (table.DataSet != null) dataSet.Tables.Add(table.Copy()); else dataSet.Tables.Add(table); } return dataSet; } public static DataRow LastRow(DataTable table) { if (table.Rows.Count == 0) return null; return table.Rows[table.Rows.Count - 1]; } public static void RemoveKeyConstraints(DataTable table) { foreach (DataColumn column in table.PrimaryKey) { column.AllowDBNull = true; column.ReadOnly = false; } } public static DataTable GroupCount(DataTable table, string[] columnNames, string countColumnName) { DataTable resultTable = new DataTable(); List keyColumns = new List(); foreach (string columnName in columnNames) { DataColumn sourceColumn = table.Columns[columnName]; DataColumn resultColumn = resultTable.Columns.Add(sourceColumn.ColumnName, sourceColumn.DataType); keyColumns.Add(resultColumn); } resultTable.Columns.Add(countColumnName, typeof(Int32)); resultTable.PrimaryKey = keyColumns.ToArray(); foreach (DataRow sourceRow in table.Rows) { List key = new List(); foreach (string columnName in columnNames) key.Add(sourceRow[columnName]); DataRow resultRow = resultTable.Rows.Find(key.ToArray()); if (resultRow == null) { resultRow = resultTable.NewRow(); foreach (string columnName in columnNames) resultRow[columnName] = sourceRow[columnName]; resultRow[countColumnName] = 0; resultTable.Rows.Add(resultRow); } resultRow[countColumnName] = (int)resultRow[countColumnName] + 1; } return resultTable; } public static DataTable CountOccurrence(DataTable table, string columnName) { Type type = table.Columns[columnName].DataType; return (DataTable) typeof(Spludlow.Data.ADO).GetMethod("CountOccurrenceWork").MakeGenericMethod(type).Invoke(null, new object[] { table, columnName }); } public static DataTable CountOccurrenceWork(DataTable table, string columnName) { string countColumnName = "Count"; Dictionary count = new Dictionary(); int nullCount = 0; foreach (DataRow row in table.Rows) { if (row.IsNull(columnName) == true) { ++nullCount; continue; } T value = (T)row[columnName]; if (count.ContainsKey(value) == false) count.Add(value, 0); ++count[value]; } DataTable resultTable = new DataTable(); resultTable.Columns.Add(countColumnName, typeof(int)); resultTable.Columns.Add(columnName, typeof(T)); foreach (T key in count.Keys) resultTable.Rows.Add(count[key], key); if (nullCount > 0) resultTable.Rows.Add(nullCount, DBNull.Value); DataView view = new DataView(resultTable); view.Sort = countColumnName + " DESC"; DataTable viewTable = resultTable.Clone(); foreach (DataRowView rowView in view) viewTable.ImportRow(rowView.Row); return viewTable; } public static DataSet Normalization(string[] textTableNames, Encoding encoding, string[] columnNames) { DataSet result = new DataSet(); Dictionary> valueCounts = new Dictionary>(); foreach (string columnName in columnNames) valueCounts.Add(columnName, new Dictionary(StringComparer.OrdinalIgnoreCase)); foreach (string textTableName in textTableNames) { DataTable table = Spludlow.Data.TextTable.ReadFile(textTableName, encoding); foreach (string columnName in columnNames) NormalizationTableRows(table, columnName, valueCounts[columnName]); } foreach (string columnName in columnNames) NormalizationAddResult(columnName, valueCounts[columnName], result); return result; } public static DataSet Normalization(DataTable table, string[] columnNames) { DataSet result = new DataSet(); foreach (string columnName in columnNames) { Dictionary valueCounts = new Dictionary(StringComparer.OrdinalIgnoreCase); NormalizationTableRows(table, columnName, valueCounts); NormalizationAddResult(columnName, valueCounts, result); } return result; } private static void NormalizationTableRows(DataTable table, string columnName, Dictionary valueCounts) { if (table.Columns[columnName].DataType != typeof(string)) throw new ApplicationException("Normalization only works with String columns: " + columnName); foreach (DataRow row in table.Rows) { if (row.IsNull(columnName) == true) continue; string value = (string)row[columnName]; if (valueCounts.ContainsKey(value) == false) valueCounts.Add(value, 0); valueCounts[value] = valueCounts[value] + 1; } } private static void NormalizationAddResult(string columnName, Dictionary valueCounts, DataSet result) { DataTable valuesTable = new DataTable(); valuesTable.TableName = columnName; valuesTable.Columns.Add("Count", typeof(int)); valuesTable.Columns.Add(columnName, typeof(string)); foreach (string key in valueCounts.Keys) valuesTable.Rows.Add(new object[] { valueCounts[key], key }); DataView view = new DataView(valuesTable); view.Sort = "Count DESC, " + columnName; DataTable sortedTable = valuesTable.Clone(); foreach (DataRowView rowView in view) sortedTable.ImportRow(rowView.Row); result.Tables.Add(sortedTable); } public static DataTable InsertColumns(DataTable table, string[] insertTextTable) { DataTable newTable = Spludlow.Data.TextTable.ReadText(insertTextTable); foreach (DataColumn column in table.Columns) newTable.Columns.Add(column.ColumnName, column.DataType); foreach (DataRow row in table.Rows) newTable.ImportRow(row); newTable.TableName = table.TableName; return newTable; } public static DataTable NameLastTable(DataSet dataSet, string tableName) { string useTableName = tableName; int existingCount = 2; while (dataSet.Tables.Contains(useTableName) == true) { useTableName = tableName + "_" + existingCount; ++existingCount; } DataTable table = dataSet.Tables[dataSet.Tables.Count - 1]; table.TableName = useTableName; return table; } public static DataTable Clone(DataTable table, string[] columnMap) { List maps = new List(); foreach (string line in columnMap) maps.Add(Spludlow.Text.Split(line, '\t', true, false)); DataTable resultTable = new DataTable(); foreach (string[] map in maps) { DataColumn column = table.Columns[map[0]]; resultTable.Columns.Add(map[1], column.DataType); } foreach (DataRow row in table.Rows) { DataRow resultRow = resultTable.NewRow(); foreach (string[] map in maps) resultRow[map[1]] = row[map[0]]; resultTable.Rows.Add(resultRow); } return resultTable; } public static DataTable SerialUnique(DataTable table, string[] columnNames) { DataTable resultsTable = table.Clone(); string[] previous = new string[columnNames.Length]; for (int rowIndex = 0; rowIndex < table.Rows.Count; ++rowIndex) { DataRow row = table.Rows[rowIndex]; bool match = true; for (int index = 0; index < columnNames.Length; ++index) { string data = (string)row[columnNames[index]]; if (previous[index] != data) match = false; previous[index] = data; } if (rowIndex != 0 && match == true) continue; resultsTable.ImportRow(row); } return resultsTable; } public static DataTable TableFromView(DataView view) { DataTable table = view.Table.Clone(); foreach (DataRowView rowView in view) table.ImportRow(rowView.Row); return table; } public static DataTable TruncateTable(DataTable table, int maxRowCount) { if (table.Rows.Count <= maxRowCount) return table; DataTable resultTable = table.Clone(); foreach (DataRow row in table.Rows) { resultTable.ImportRow(row); if (resultTable.Rows.Count == maxRowCount) break; } return resultTable; } public static DataSet PagedQuery(DataTable table, string rowFilter, string sort, int pageIndex, int pageSize) { DataTable resultTable = table.Clone(); DataView view = new DataView(table); if (rowFilter != null && rowFilter.Length > 0) view.RowFilter = rowFilter; if (sort != null && sort.Length > 0) view.Sort = sort; if (pageIndex < 0) pageIndex = 0; int startIndex = pageIndex * pageSize; int searchRecords = view.Count; int totalRecords = table.Rows.Count; for (int index = 0; index < pageSize && startIndex + index < searchRecords; ++index) { resultTable.ImportRow(view[startIndex + index].Row); } DataSet dataSet = new DataSet(); resultTable.TableName = "Result"; dataSet.Tables.Add(resultTable); int totalPages = totalRecords / pageSize; if ((totalRecords % pageSize) != 0) ++totalPages; int searchPages = searchRecords / pageSize; if ((searchRecords % pageSize) != 0) ++searchPages; DataTable infoTable = Spludlow.Data.TextTable.ReadText(new string[] { "FilterRecords FilterPages TotalRecords TotalPages", "Int32 Int32 Int32 Int32", }); infoTable.Rows.Add(new object[] { searchRecords, searchPages, totalRecords, totalPages }); infoTable.TableName = "Info"; dataSet.Tables.Add(infoTable); return dataSet; } public static DataSet Schema(DataTable table) { return Schema(table, false); } public static DataSet Schema(DataTable table, bool longest) { return Schema(new DataTable[] { table }, longest); } public static DataSet Schema(DataSet dataSet) { return Schema(dataSet, false); } public static DataSet Schema(DataSet dataSet, bool longest) { List tables = new List(); foreach (DataTable table in dataSet.Tables) tables.Add(table); return Schema(tables.ToArray(), longest); } public static DataSet Schema(DataTable[] tables) { return Schema(tables, false); } public static DataSet Schema(DataTable[] tables, bool longest) { DataSet schemaDataSet = new DataSet(); foreach (DataTable table in tables) { List primaryKeyColumnNames = new List(); foreach (DataColumn pkColumn in table.PrimaryKey) primaryKeyColumnNames.Add(pkColumn.ColumnName); Dictionary longestColumns = new Dictionary(); if (longest == true) { List useColumns = new List(); foreach (DataColumn column in table.Columns) { if (column.DataType == typeof(string)) { longestColumns.Add(column.ColumnName, 0); useColumns.Add(column.ColumnName); } } foreach (DataRow row in table.Rows) { foreach (string columnName in useColumns) { if (row.IsNull(columnName) == true) continue; int length = ((string)row[columnName]).Length; if (length == 0) continue; if (length > longestColumns[columnName]) longestColumns[columnName] = length; } } } DataTable columnsTable = Spludlow.Data.Schemas.NewSchemaColumnsTable(table.TableName); foreach (DataColumn column in table.Columns) { bool primaryKey = primaryKeyColumnNames.Contains(column.ColumnName); int longestLength = -1; if (longest == true && longestColumns.ContainsKey(column.ColumnName) == true) longestLength = longestColumns[column.ColumnName]; int precision = 0; int scale = 0; if (column.DataType == typeof(Decimal)) { precision = 19; scale = 4; } Type dataType = column.DataType; if (dataType.IsEnum == true) dataType = typeof(Enum); DataRow schemaRow = columnsTable.NewRow(); schemaRow["ColumnName"] = column.ColumnName; schemaRow["Ordinal"] = column.Ordinal; schemaRow["DataTypeId"] = Spludlow.Data.Schemas.NativeToCommon(dataType.Name, "TypeCode"); schemaRow["MaxLength"] = column.MaxLength; schemaRow["Precision"] = precision; schemaRow["Scale"] = scale; schemaRow["PrimaryKey"] = primaryKey; schemaRow["AllowDBNull"] = column.AllowDBNull; schemaRow["AutoIncrement"] = column.AutoIncrement; schemaRow["Longest"] = longestLength; columnsTable.Rows.Add(schemaRow); } Spludlow.Data.Schemas.TidySchemaTable(columnsTable); schemaDataSet.Tables.Add(columnsTable); Spludlow.SysTables.SchemaKeysDataTable keysTable = Spludlow.Data.Schemas.NewSchemaKeysTable(table.TableName); string primaryKeyName = "PK_" + table.TableName; for (int index = 0; index < primaryKeyColumnNames.Count; ++index) { string primaryKeyColumnName = primaryKeyColumnNames[index]; Spludlow.SysTables.SchemaKeysRow keyRow = keysTable.NewSchemaKeysRow(); keyRow.KeyName = primaryKeyName; keyRow.KeyType = "P"; keyRow.Ordinal = index; keyRow.Descending = false; keyRow.ColumnName = primaryKeyColumnName; keyRow.ParentTable = null; keyRow.ParentColumn = null; keysTable.Rows.Add(keyRow); } schemaDataSet.Tables.Add(keysTable); } return schemaDataSet; } public static DataTable TableCreate(string tableName, DataSet schema) { return TableCreate(tableName, schema.Tables[tableName + "_Columns"], schema.Tables[tableName + "_Keys"]); } public static DataTable TableCreate(string tableName, DataTable schemaColumns, DataTable schemaKeys) // Only doing PK no other index for FKs { DataTable table = new DataTable(tableName); List primaryKeyColumns = new List(); foreach (Spludlow.SysTables.SchemaColumnsRow columnRow in schemaColumns.Select(null, "Ordinal")) { string nativeDataType = Spludlow.Data.Schemas.CommonToNative(columnRow.DataTypeId, "TypeCode"); Type type = Type.GetType("System." + nativeDataType, true); DataColumn column = table.Columns.Add(columnRow.ColumnName, type); if (nativeDataType == "String") column.MaxLength = columnRow.MaxLength; column.AllowDBNull = columnRow.AllowDBNull; column.AutoIncrement = columnRow.AutoIncrement; if (columnRow.PrimaryKey == true) primaryKeyColumns.Add(column); } table.PrimaryKey = primaryKeyColumns.ToArray(); return table; } public static DataSet AddSchema(DataSet dataSet) { return AddSchema(dataSet, false); } public static DataSet AddSchema(DataSet dataSet, bool longest) { List tableNames = new List(); foreach (DataTable table in dataSet.Tables) tableNames.Add(table.TableName); DataSet schema = Schema(dataSet, longest); DataSet resultDataSet = new DataSet(); foreach (string tableName in tableNames) { DataTable dataTable = dataSet.Tables[tableName]; DataTable columnsTable = schema.Tables[tableName + "_Columns"]; DataTable keysTable = schema.Tables[tableName + "_Keys"]; dataSet.Tables.Remove(dataTable); schema.Tables.Remove(columnsTable); schema.Tables.Remove(keysTable); resultDataSet.Tables.Add(dataTable); resultDataSet.Tables.Add(columnsTable); resultDataSet.Tables.Add(keysTable); } return resultDataSet; } public static DataTable FixEnumColumns(DataTable table) { List columnNames = new List(); foreach (DataColumn column in table.Columns) { Type type = column.DataType; if (type.IsEnum == false) continue; string assemblyFullName = type.Assembly.FullName; if (assemblyFullName.StartsWith("mscorlib") == true || assemblyFullName.StartsWith("System.") == true) continue; columnNames.Add(column.ColumnName); Spludlow.Log.Warning("ADO FixEnumColumns: Converting: " + type.FullName + ", " + table.TableName + "." + column.ColumnName); } DataTable resultTable = table.Clone(); Dictionary converted = new Dictionary(); foreach (string columnName in columnNames) { converted.Add(columnName, new string[table.Rows.Count]); Type type = table.Columns[columnName].DataType; for (int index = 0; index < table.Rows.Count; ++index) { DataRow row = table.Rows[index]; if (row.IsNull(columnName) == true) continue; int enumValue = (int)row[columnName]; converted[columnName][index] = Enum.GetName(type, enumValue); row[columnName] = DBNull.Value; } resultTable.Columns[columnName].DataType = typeof(String); } for (int index = 0; index < table.Rows.Count; ++index) { resultTable.ImportRow(table.Rows[index]); foreach (string columnName in columnNames) { resultTable.Rows[index][columnName] = converted[columnName][index]; } } return resultTable; } public static DataTable EnumInt32Report(Type enumType) { DataTable table = Spludlow.Data.TextTable.ReadText(new string[] { "Number Name", "Int32 String", }); foreach (int number in Enum.GetValues(enumType)) { string name = Enum.GetName(enumType, number); table.Rows.Add(new object[] { number, name }); } table.TableName = enumType.Name; Spludlow.Log.Report("EnumInt32Report: " + enumType.Name, new object[] { table }); return table; } public static DataSet RenameTablesAndColumnsTemplate(DataSet dataSet) { DataTable tableNames = Spludlow.Data.TextTable.ReadText("TableNames", new string[] { "SourceTableName TargetTableName", "String* String", }); DataTable columnames = Spludlow.Data.TextTable.ReadText("ColumnNames", new string[] { "SourceTableName SourceColumnName TargetColumnName", "String* String* String", }); foreach (DataTable table in dataSet.Tables) { tableNames.Rows.Add(table.TableName, table.TableName); foreach (DataColumn column in table.Columns) columnames.Rows.Add(table.TableName, column.ColumnName, column.ColumnName); } DataSet result = new DataSet(); result.Tables.Add(tableNames); result.Tables.Add(columnames); return result; } public static void RenameTablesAndColumns(DataSet dataSet, DataSet renameNamesDataSet) { foreach (DataRow row in renameNamesDataSet.Tables["ColumnNames"].Rows) { string sourceTablename = (string)row["SourceTableName"]; string sourceColumnName = (string)row["SourceColumnName"]; string targetColumnName = (string)row["TargetColumnName"]; if (sourceColumnName == targetColumnName) continue; DataTable table = dataSet.Tables[sourceTablename]; table.Columns[sourceColumnName].ColumnName = targetColumnName; } foreach (DataRow row in renameNamesDataSet.Tables["TableNames"].Rows) { string sourceTablename = (string)row["SourceTableName"]; string targetTableName = (string)row["TargetTableName"]; if (sourceTablename == targetTableName) continue; DataTable table = dataSet.Tables[sourceTablename]; table.TableName = targetTableName; } } public static DataTable ReflectNewTable(Type instanceType) { return ReflectNewTable(new DataTable(), instanceType); } public static DataTable ReflectNewTable(DataTable table, Type instanceType) { foreach (FieldInfo fieldInfo in instanceType.GetFields()) { if (Spludlow.SimpleEncoding.IsSimple(fieldInfo.FieldType) == true) table.Columns.Add(fieldInfo.Name, fieldInfo.FieldType); } foreach (PropertyInfo propertyInfo in instanceType.GetProperties()) { if (Spludlow.SimpleEncoding.IsSimple(propertyInfo.PropertyType) == true) table.Columns.Add(propertyInfo.Name, propertyInfo.PropertyType); } return table; } public static DataRow ReflectNewRow(DataTable table, object instance) { DataRow row = table.NewRow(); foreach (FieldInfo fieldInfo in instance.GetType().GetFields()) { if (table.Columns.Contains(fieldInfo.Name) == false) continue; object value = fieldInfo.GetValue(instance); if (value == null) continue; row[fieldInfo.Name] = value; } foreach (PropertyInfo propertyInfo in instance.GetType().GetProperties()) { if (table.Columns.Contains(propertyInfo.Name) == false) continue; object value = propertyInfo.GetValue(instance); if (value == null) continue; row[propertyInfo.Name] = value; } table.Rows.Add(row); return row; } } }