Как объединить две таблицы данных с помощью PrimaryKeys?

У меня есть две таблицы данных, и я хочу объединить столбцы и создать третью таблицу.

//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

Каков ожидаемый результат?

Tim Schmelter 25.07.2019 12:09

dtResult должен иметь все столбцы (A,B,C,D,a,b,c,d). Ключевые столбцы не являются обязательными для включения.

Prem 25.07.2019 12:10
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
2
566
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

По-видимому, 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 достаточно. Спасибо еще раз!

Prem 25.07.2019 12:28

Ну, я прочитал причину в каком-то блоге, которая также упоминалась в вопросе, но каким-то образом я удалил строку после редактирования вопроса. Но не знал, как это решить. Теперь это работает.

Prem 25.07.2019 12:32

В дополнение к ответу @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, если это необходимо.

Другие вопросы по теме