У меня есть две таблицы данных, и я хочу объединить столбцы и создать третью таблицу.
//Given
dt1 {A(PK),B,C,D}
dt2 {a(PK),b,c,d}
//Want
dtResult {A,B,C,D,a,b,c,d}
Не хотите терять ExtendedProperties, поэтому не выбирайте DataColumn.ColumnName и не добавляйте в столбцы.
Код:
DataTable dt1 = new DataTable();
dt1.TableName = "dt1";
dt1.PrimaryKey = new DataColumn[] { dt1.Columns.Add("A") };
dt1.Columns.Add("B");
dt1.Columns.Add("C");
dt1.Columns.Add("D");
DataTable dt2 = new DataTable();
dt2.TableName = "dt2";
dt2.PrimaryKey = new DataColumn[] { dt2.Columns.Add("a") };
dt2.Columns.Add("b");
dt2.Columns.Add("c");
dt2.Columns.Add("d");
var dtResult = dt1.Clone();
dtResult.TableName = "dtResult";
До сих пор работает нормально
Теперь хочу слиться...
Несколько попыток слияния, тип 1
dtResult.Merge(dt2.Clone());
dtResult.Merge(dt2.Clone(), false);
dtResult.Merge(dt2.Clone(), true);
dtResult.Merge(dt2.Clone(), false, MissingSchemaAction.Add);
dtResult.Merge(dt2.Clone(), false, MissingSchemaAction.AddWithKey);
dtResult.Merge(dt2.Clone(), true, MissingSchemaAction.Add);
dtResult.Merge(dt2.Clone(), true, MissingSchemaAction.AddWithKey);
Во всех вышеперечисленных попытках столбцы merged входят в dtResult, но выбрасывают NullReferenceException.
Трассировки стека:
System.NullReferenceException
HResult=0x80004003
Message=Object reference not set to an instance of an object.
Source=System.Data
StackTrace:
at System.Data.Merger.MergeSchema(DataTable table)
at System.Data.Merger.MergeTableData(DataTable src)
at System.Data.Merger.MergeTable(DataTable src)
at System.Data.DataTable.Merge(DataTable table, Boolean preserveChanges, MissingSchemaAction missingSchemaAction)
at Demo.Program.Test5() in C:\App\Demo\Program.cs:line 54
at Demo.Program.Main(String[] args) in C:\App\Program.cs:line 36
Несколько попыток слияния, тип 2
dtResult.Merge(dt2.Clone(), false, MissingSchemaAction.Error);
dtResult.Merge(dt2.Clone(), true, MissingSchemaAction.Error);
Во всех вышеперечисленных попытках столбцы NOT merged в dtResult и System.Data.DataException
Трассировки стека:
System.Data.DataException
HResult=0x80131920
Message=Target table missing definition for column a.
Source=System.Data
StackTrace:
at System.Data.Merger.MergeSchema(DataTable table)
at System.Data.Merger.MergeTableData(DataTable src)
at System.Data.Merger.MergeTable(DataTable src)
at System.Data.DataTable.Merge(DataTable table, Boolean preserveChanges, MissingSchemaAction missingSchemaAction)
at Demo.Program.Test5() in C:\App\Demo\Program.cs:line 54
at Demo.Program.Main(String[] args) in C:\App\Demo\Program.cs:line 36
Несколько попыток слияния, тип 3
dtResult.Merge(dt2.Clone(), false, MissingSchemaAction.Ignore);
dtResult.Merge(dt2.Clone(), true, MissingSchemaAction.Ignore);
Во всех вышеперечисленных попытках столбцы NOT merged в dtResult и NO exception
dtResult должен иметь все столбцы (A,B,C,D,a,b,c,d). Ключевые столбцы не являются обязательными для включения.





По-видимому, NullReferenceException возникает из-за того, что две таблицы имеют первичные ключи. Нам нужно что-то сделать, чтобы избежать этого конфликта.
Ну вот:
var dtResult = dt1.Clone();
dtResult.TableName = "dtResult";
var dt2Cloned = dt2.Clone();
dt2Cloned.PrimaryKey = null;
dtResult.Merge(dt2Cloned);
var primaryKeys = dtResult.PrimaryKey.ToList();
foreach (var col in dt2.PrimaryKey)
{
primaryKeys.Add(dtResult.Columns[col.ColumnName]);
}
dtResult.PrimaryKey = primaryKeys.ToArray();
Это, вероятно, можно немного оптимизировать, но это даст вам нужный результат, так что это хорошее начало.
Большое спасибо @Ahmed Abdelhameed. Создание PrimaryKey=null не пришло мне в голову, вместо этого я пытался удалить этот столбец. Поскольку я не забочусь о повторном применении ключей в новой таблице, поэтому PrimaryKey=null достаточно. Спасибо еще раз!
Ну, я прочитал причину в каком-то блоге, которая также упоминалась в вопросе, но каким-то образом я удалил строку после редактирования вопроса. Но не знал, как это решить. Теперь это работает.
В дополнение к ответу @Ahmed Abdelhameed.
Если вы столкнулись с такой проблемой, как Unique column cannot have same value или null is not allowed, добавьте код ниже.
var dt2Cloned = dt2.Clone();
var pks = dt2Cloned.PrimaryKey.ToList();
dt2Cloned.PrimaryKey = null;
pks.ForEach(pk => { pk.Unique = false; pk.AllowDBNull = true; });
Вы также можете сделать то же самое для PKs из dt1, если это необходимо.
Каков ожидаемый результат?