Skip to content

Commit 87a5517

Browse files
committed
fix(datatable): validate input and improve schema comparison in MergeTables
1 parent ec153b6 commit 87a5517

1 file changed

Lines changed: 35 additions & 15 deletions

File tree

SharpHelpers/SharpHelpers/DataTableHelper.cs

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ public static void AddColumn<T>(this DataTable table, string columnName, T defau
104104
{
105105
row[columnName] = defaultValue!;
106106
}
107-
}
107+
}
108108

109109
/// <summary>
110110
/// Merges multiple DataTables with the same schema into one.
@@ -115,30 +115,50 @@ public static void AddColumn<T>(this DataTable table, string columnName, T defau
115115
public static DataTable MergeTables(IEnumerable<DataTable> tables)
116116
{
117117
if (tables == null) throw new ArgumentNullException(nameof(tables));
118+
var list = tables.Where(t => t != null).ToList();
119+
if (list.Count == 0) throw new ArgumentException("No tables.");
118120

119-
var resultTable = tables.First().Clone();
120-
foreach (var table in tables)
121+
var result = list[0].Clone();
122+
foreach (var t in list)
121123
{
122-
if (!AreSchemasCompatible(resultTable, table))
124+
if (!AreSchemasCompatible(result, t))
123125
throw new ArgumentException("Tables have incompatible schemas.");
124-
125-
foreach (DataRow row in table.Rows)
126+
foreach (DataRow r in t.Rows)
126127
{
127-
resultTable.ImportRow(row);
128+
result.ImportRow(r);
128129
}
129130
}
130-
return resultTable;
131+
132+
return result;
131133
}
132134

133-
private static bool AreSchemasCompatible(DataTable table1, DataTable table2)
135+
/// <summary>
136+
/// Determines whether two <see cref="DataTable"/> instances have compatible schemas
137+
/// for position-based operations (e.g., cloning and row import).
138+
/// </summary>
139+
/// <param name="table1">
140+
/// The first table whose schema is used as the reference (column order matters).
141+
/// </param>
142+
/// <param name="table2">
143+
/// The second table to compare against <paramref name="table1"/>.
144+
/// </param>
145+
/// <returns>
146+
/// <c>true</c> if both tables have the same number of columns and, at each position,
147+
/// the column name matches (case-insensitive) and the <see cref="Type"/> matches;
148+
/// otherwise, <c>false</c>.
149+
/// </returns>
150+
/// <remarks>
151+
/// This check is strictly positional: it does not attempt to realign columns by name.
152+
/// Extended properties, nullability metadata, constraints, and keys are not compared.
153+
/// </remarks>
154+
private static bool AreSchemasCompatible(DataTable a, DataTable b)
134155
{
135-
if (table1.Columns.Count != table2.Columns.Count) return false;
136-
137-
for (int i = 0; i < table1.Columns.Count; i++)
156+
if (a.Columns.Count != b.Columns.Count) return false;
157+
for (int i = 0; i < a.Columns.Count; i++)
138158
{
139-
if (table1.Columns[i].ColumnName != table2.Columns[i].ColumnName ||
140-
table1.Columns[i].DataType != table2.Columns[i].DataType)
141-
return false;
159+
var ca = a.Columns[i]; var cb = b.Columns[i];
160+
if (!ca.ColumnName.Equals(cb.ColumnName, StringComparison.OrdinalIgnoreCase)) return false;
161+
if (ca.DataType != cb.DataType) return false;
142162
}
143163
return true;
144164
}

0 commit comments

Comments
 (0)