none
Слияние двух DataTable C# RRS feed

  • Вопрос

  • Приветствую.

    Хочу сделать импорт из одного файла базы в другой. Структуры баз одинаковые - одинаковое число столбцов. Представляю себе только начальную стадию решения этой задачи. Загружаю две базы в разные DataTable. DataTable.Merge() не совсем подойдет, ибо могут быть повторения. Каким способом можно произвести слияние без повторений?

    Спасибо.

    12 марта 2013 г. 5:32

Ответы

  • Проблема автогенерацией id не решится. Нужна сквозная нумерация записей через все файлы БД, а т.к. они никак не связаны - то решить это врядли получится. Вам нужно придумывать скорей всего механизм версионности какой то, например хранить старую (уже залитую БД в центральную) и измененнную версии БД клиента до момента очередной отправки изменений в централизованную БД, имея новую и предыдующую версии клиентской БД - должна быть возможноть получить новые строки, которые точно можно вставить в центральную БД. А также сможете получить измененные строки. Но вот как соотносить измененные строки с теми строками, что уже есть в центральной БД - это вопрос.  Возможно создать специальную техническую таблицу в БД, которая будет хранить сопоставление id записи в центральной БД - id в пользовательской и само имя или идентификатор пользователя, чья это бд.

    Надеюсь мои размышления вам помогут.


    Для связи [mail]

    21 марта 2013 г. 11:41

Все ответы

  • Насколько помню метод Merge() объединяет повторяющиеся данные, т.е. при слиянии будет только одна строка. Так что он должен вам подойти.
    12 марта 2013 г. 6:06
    Модератор
  • Увы. Открывал один и тот же файл, в котором 2 записи. По итогу - 4 записи.
    12 марта 2013 г. 6:37
  • Странно, вот пример из MSDN работает

    namespace Test
    {
      class Program
      {
        static void Main(string[] args)
        {
          DemonstrateMergeTable();
        }
        private static void DemonstrateMergeTable()
        {
          DataTable table1 = new DataTable("Items");
    
          // Add columns
          DataColumn column1 = new DataColumn("id", typeof(System.Int32));
          DataColumn column2 = new DataColumn("item", typeof(System.Int32));
          table1.Columns.Add(column1);
          table1.Columns.Add(column2);
    
          // Set the primary key column.
          table1.PrimaryKey = new DataColumn[] { column1 };
    
          // Add RowChanged event handler for the table.
          table1.RowChanged +=
              new System.Data.DataRowChangeEventHandler(Row_Changed);
    
          // Add some rows.
          DataRow row;
          for (int i = 0; i <= 3; i++)
          {
            row = table1.NewRow();
            row["id"] = i;
            row["item"] = i;
            table1.Rows.Add(row);
          }
    
          // Accept changes.
          table1.AcceptChanges();
          PrintValues(table1, "Original values");
    
          // Create a second DataTable identical to the first.
          DataTable table2 = table1.Clone();
    
          // Add three rows. Note that the id column can't be the 
          // same as existing rows in the original table.
          row = table2.NewRow();
          row["id"] = 1;
          row["item"] = 1;
          table2.Rows.Add(row);
    
          row = table2.NewRow();
          row["id"] = 12;
          row["item"] = 555;
          table2.Rows.Add(row);
    
          row = table2.NewRow();
          row["id"] = 13;
          row["item"] = 665;
          table2.Rows.Add(row);
    
          // Merge table2 into the table1.
          Console.WriteLine("Merging");
          table1.Merge(table2);
          PrintValues(table1, "Merged With table1");
    
        }
    
        private static void Row_Changed(object sender,
            DataRowChangeEventArgs e)
        {
          Console.WriteLine("Row changed {0}\t{1}",
              e.Action, e.Row.ItemArray[0]);
        }
    
        private static void PrintValues(DataTable table, string label)
        {
          // Display the values in the supplied DataTable:
          Console.WriteLine(label);
          foreach (DataRow row in table.Rows)
          {
            foreach (DataColumn col in table.Columns)
            {
              Console.Write("\t " + row[col].ToString());
            }
            Console.WriteLine();
          }
        }
      }
    }

    Может у вас первичный ключ отсутствует и поэтому записи дублируются.

    12 марта 2013 г. 6:42
    Модератор
  • В общем, чтобы вы поняли идею того, что я хочу, я опишу задачу. Есть файлы баз данных. Один будет находится в одном месте, другой в другом, третий в третьем. Все заполняют эти файлы локально. Затем, либо на флешке, либо по мылу привезут в первое место, где нужно будет все это дело соединить воедино. Т. о. в колонке id могут быть повторяющиеся значения. Выход из этой ситуации я вижу в том, чтобы при выборке из импортируемых баз выбирать все поля, кроме id.

    Но надо учесть и тот момент, что файлы импортируемых баз будут передавать ни один раз. Т.е. если в нем забито изначально 2к записей, добьют еще 100 записей и перешлют для слияния. Программа должна будет по новой пробегать все строки и смотреть изменения. Нагрузочная какая-то процедура с учетом того, что в итоговой БД будет 30к записей и надо будет перебирать все для сверки.

    Подскажите, пожалуйста, как тут лучше организовать. Merge() по-прежнему пойдёт?

    Спасибо.

    12 марта 2013 г. 17:53
  •         private void Import()
            {
                const string queryFirst = @"select * from Patient";
                const string querySecond = @"select podrazdelenie, dislocation, medcardnumber, familia, name, otchestvo, birthdate, sex from Patient";
                string connectionStringFirst = String.Format("Data Source={0}", textBox1.Text);
                string connectionStringSecond = String.Format("Data Source={0}", textBox2.Text);
    
                try
                {
                    _helper = new DbHelper(connectionStringFirst);
                    if (!_helper.Load(queryFirst)) return;
                    DataTable firstDataTable = _helper.DataTable;
    
                    _helper = new DbHelper(connectionStringSecond);
                    if (!_helper.Load(querySecond)) return;
                    DataTable secondDataTable = _helper.DataTable;
    
                    firstDataTable.Merge(secondDataTable);
    
                    _helper = new DbHelper(connectionStringFirst);
                    _helper.Load(queryFirst, "id");
                    _helper.DataTable = firstDataTable;
                    //_helper.DataTable.AcceptChanges();
                    _helper.Save();
                }
                catch (Exception fail)
                {
                    String error = "Произошла следующая ошибка: ";
                    error += fail.Message + "\n\n";
                    MessageBox.Show(error, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }

    Вот метод Save():

            public bool Save()
            {
                if (String.IsNullOrEmpty(_fieldNameId)) return false;
    
                try
                {
                    _connection.Open();
                    _dataAdapter.Update(_dataTable);
    
                    return true;
                }
                catch (Exception fail)
                {
                    String error = "Произошла следующая ошибка: ";
                    error += fail.Message + "\n\n";
                    MessageBox.Show(error, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return false;
                }
                finally
                {
                    _connection.Close();
                }
            }

    Почему не происходит сохранение данных в файл? У dataAdapter все команда инициализированы. Что я делаю не так?

    Спасибо.

    13 марта 2013 г. 7:05
  • Помогите, пожалуйста.

    Крыша уже слетает...

    13 марта 2013 г. 12:08
  • Привет

    Мердж данных без id и каких-либо уникальных данных, по которым можно сопоставить строки в разных (физически) таблицах  - так и будет плодить дубликаты. Также вы столкнетесь с проблемой обновления данных, т.к. нужно понимать по какому критерию искать строку для обновления в вашей итоговой таблице.

    По поводу сохранения файла - сам файл БД случайно не добавлен в проект Visual Studio и не стоит ли у него свойство копировать всегда в Output папку? Иначе у вас всегда при запуске проекта файлы база данных будет заменяться на старую.


    Для связи [mail]

    • Предложено в качестве ответа Abolmasov Dmitry 25 марта 2013 г. 8:50
    18 марта 2013 г. 8:12
  • Приветствую, Дмитрий.

    Если я правильно понял, то из импортируемой БД надо брать все столбцы вместе с id? На мсдн'е нашел эту статью: http://msdn.microsoft.com/ru-ru/library/ks9f57t0(v=vs.90).aspx

    Что вы посоветуете для решения проблемы с обновлением данных?

    Нет, сам файл БД в проект не добавлен. Его выбирает пользователь из программы всегда сам с помощью OpenFileDialog. Так что тут что-то другое.

    Спасибо.

    18 марта 2013 г. 17:03
  • Проблема автогенерацией id не решится. Нужна сквозная нумерация записей через все файлы БД, а т.к. они никак не связаны - то решить это врядли получится. Вам нужно придумывать скорей всего механизм версионности какой то, например хранить старую (уже залитую БД в центральную) и измененнную версии БД клиента до момента очередной отправки изменений в централизованную БД, имея новую и предыдующую версии клиентской БД - должна быть возможноть получить новые строки, которые точно можно вставить в центральную БД. А также сможете получить измененные строки. Но вот как соотносить измененные строки с теми строками, что уже есть в центральной БД - это вопрос.  Возможно создать специальную техническую таблицу в БД, которая будет хранить сопоставление id записи в центральной БД - id в пользовательской и само имя или идентификатор пользователя, чья это бд.

    Надеюсь мои размышления вам помогут.


    Для связи [mail]

    21 марта 2013 г. 11:41