Странный эффект DataSet функция Merge
От: Onizuka  
Дата: 27.04.07 19:25
Оценка:
Перед тем как решиться написать вопрос облазил весь RSDN в поиске по ключевым словам DataSet и Merge. Ответа не нашел.
Лучшее описание вопроса — это исходник
Суть проблемы такова — у меня есть датасет myDataSet(упрощенный вариант состоит из одной таблицы), я в него из БД считываю данные. Затем добавляю непосредственно в таблицу DataSet-a одну строку, делаю GetChanges() для него, и полученый датасет с изменениями nChangesSet синхронизирую с базой данных — dataadapter.update(nChangesSet). После этого Соединяю эти 2 датасета в надежде,что информация в исходном myDataSet обновится с помощью nChangesSet(В частности поле ключа)
А получаю следующий результат — вместо одной записи с нормальным ключом(таким же как и запись в БД), myDataSet содержит 2 записи, одну со значением ключевого поля датасета(предположим 0), а вторая запись уже содержит нормальное значение ключа(предположим 678).
Что это за херня такая и как с ней бороться???

public void TestFunc()
{

#region createDataSet

DataSet myDataSet = new DataSet("MyDataSet");
DataTable myLineTable = new DataTable("Line");
DataColumn idColumn = new DataColumn("Line_ID", typeof(int));
idColumn.AutoIncrement=true;
DataColumn FPXColumn = new DataColumn("First_Point_X", typeof(int));
DataColumn FPYColumn = new DataColumn("First_Point_Y", typeof(int));
DataColumn SPXColumn = new DataColumn("Second_Point_X", typeof(int));
DataColumn SPYColumn = new DataColumn("Second_Point_Y", typeof(int));
DataColumn WidthColumn = new DataColumn("Width", typeof(System.Double));
DataColumn ColorColumn = new DataColumn("Color", typeof(int), null);

// DataColumn array to set primary key.
DataColumn[] keyColumn= new DataColumn[1];

// Add columns to table, and table to DataSet.
myLineTable.Columns.Add(idColumn);
myLineTable.Columns.Add(FPXColumn);
myLineTable.Columns.Add(FPYColumn);
myLineTable.Columns.Add(SPXColumn);
myLineTable.Columns.Add(SPYColumn);
myLineTable.Columns.Add(WidthColumn);
myLineTable.Columns.Add(ColorColumn);
myDataSet.Tables.Add(myLineTable);

// Set primary key column.
keyColumn[0]= idColumn;
myLineTable.PrimaryKey=keyColumn;

#endregion

//Эту строчку измените для подключения к своему SQL server
SqlConnection nConn = new SqlConnection("workstation id=DUMA;Integrated Security=SSPI;Initial Catalog=Shapes");
nConn.Open();

#region init m_lineDataAdapter

SqlDataAdapter m_lineDataAdapter = new SqlDataAdapter();
m_lineDataAdapter.TableMappings.Add("Table", "Line");

//Процедура заполнения таблицы(обычный SELECT, который выбирает все значения)
SqlCommand cmd = new SqlCommand("GetLines", nConn);
cmd.CommandType = CommandType.StoredProcedure;
m_lineDataAdapter.SelectCommand = cmd;

//Процедура вставки записи(тыходному параметру присваивается в процедуре @@IDENTITY и отобразается на поле ключа)
cmd = new SqlCommand("AddLine", nConn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter("@first_x", SqlDbType.Int, 0, "First_Point_X"));
cmd.Parameters.Add(new SqlParameter("@first_y", SqlDbType.Int, 0, "First_Point_Y"));
cmd.Parameters.Add(new SqlParameter("@second_x", SqlDbType.Int, 0, "Second_Point_X"));
cmd.Parameters.Add(new SqlParameter("@second_y", SqlDbType.Int, 0, "Second_Point_Y"));
cmd.Parameters.Add(new SqlParameter("@width_l", SqlDbType.Float, 0, "Width"));
cmd.Parameters.Add(new SqlParameter("@color_l", SqlDbType.Int, 0, "Color"));
cmd.Parameters.Add(new SqlParameter("@line_id", SqlDbType.Int, 0, ParameterDirection.Output, false, 0, 0, "Line_ID", DataRowVersion.Default, null));
cmd.UpdatedRowSource = UpdateRowSource.OutputParameters;
m_lineDataAdapter.InsertCommand = cmd;

//И Ежу понятно — удаление (не используется)
cmd = new SqlCommand("DeleteLine", nConn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter("@id", SqlDbType.Int, 0, "Line_ID"));
m_lineDataAdapter.DeleteCommand = cmd;

//Обновление(опять-таки в данном примере не используется)
cmd = new SqlCommand("UpdateLine", nConn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter("@id", SqlDbType.Int, 0, "Line_ID"));
cmd.Parameters.Add(new SqlParameter("@first_x", SqlDbType.Int, 0, "First_Point_X"));
cmd.Parameters.Add(new SqlParameter("@first_y", SqlDbType.Int, 0, "First_Point_Y"));
cmd.Parameters.Add(new SqlParameter("@second_x", SqlDbType.Int, 0, "Second_Point_X"));
cmd.Parameters.Add(new SqlParameter("@second_y", SqlDbType.Int, 0, "Second_Point_Y"));
cmd.Parameters.Add(new SqlParameter("@width_l", SqlDbType.Float, 0, "Width"));
cmd.Parameters.Add(new SqlParameter("@color_l", SqlDbType.Int, 0, "Color"));
cmd.UpdatedRowSource = UpdateRowSource.None;
m_lineDataAdapter.UpdateCommand = cmd;

#endregion

//Ради интереса заполняем(но для наглядности можно коментить, пусть датасет будет девственно чист
m_lineDataAdapter.Fill(myDataSet, "Line");

//Add new row
DataRow newRow = myLineTable.NewRow();
newRow["First_Point_X"] = 10;
newRow["First_Point_Y"] = 10;
newRow["Second_Point_X"] = 100;
newRow["Second_Point_Y"] = 100;
newRow["Width"] = 10;
newRow["Color"] = System.Drawing.Color.Black.ToArgb();
myLineTable.Rows.Add(newRow);

//Вот оно — получение изменений
DataSet nChangesSet = myDataSet.GetChanges();

//Все по прежнему хорошо, получаем обновление ключевого поля
m_lineDataAdapter.Update(nChangesSet, "Line");

//А вот тут трындец какой-то мне непонятный(myDataSet содержит 2 строки — новую и старую)
myDataSet.Merge(nChangesSet, true); //myDataSet.Merge(nChangesSet, true); или myDataSet.Merge(nChangesSet); не предлагать, имхо не помогает
myDataSet.AcceptChanges();

nConn.Close();
}

I need help!!! В чем ошибка???
Re: Странный эффект DataSet функция Merge
От: Аноним  
Дата: 27.04.07 19:56
Оценка:
Здравствуйте, Onizuka, Вы писали:

O>...


GetChanges возвращает копию датасета с изменениями.
При сохранении этой копии адаптер обновляет значение первичного ключа.
т.е.
было id = 1
стало id = N (следующее значение для данной таблицы в бд).
Слияние производится по значению первичного ключа.
Т.к. в исходном датасете строка имеет id = 1, а в датасете с изменениями id = N, то Merge добавит в исходный датасет еще одну строку с id = N.

Чтобы все получилось нужно удалить из исходного датасета все добавленные строки, а только потом делать Merge.
Re[2]: Странный эффект DataSet функция Merge
От: Onizuka  
Дата: 30.04.07 17:35
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, Onizuka, Вы писали:


O>>...


А>GetChanges возвращает копию датасета с изменениями.

А>При сохранении этой копии адаптер обновляет значение первичного ключа.
А>т.е.
А>было id = 1
А>стало id = N (следующее значение для данной таблицы в бд).
А>Слияние производится по значению первичного ключа.
А>Т.к. в исходном датасете строка имеет id = 1, а в датасете с изменениями id = N, то Merge добавит в исходный датасет еще одну строку с id = N.

А>Чтобы все получилось нужно удалить из исходного датасета все добавленные строки, а только потом делать Merge.



Хм... Этот вариант понятен, но что делать, если мы добавим строку в датасет, потом её изменим и только плосле этого синхронизируем с базой данных? Теоретически DataRowState после изменения будет равен Modified вместо Added. Или я мыслю неправильными категориями и нельза за 1 раз без синхронизацией с базой данных добавлять и изменять строки в таблице? Тогда возникает сразу следующий вопрос — Предположим мы добавим строку в дадасет и сразу ее удалим(DataRowState = Deleted) Т.е. при добавлении в датасет, первичный ключ предположим присвоится =1, а после синхронизации с базой, если в ней окажется такой же ключ, то строка с таким ключем сотрется??? Фигня какая-то получается.
Re[3]: Странный эффект DataSet функция Merge
От: Дьяченко Александр Россия  
Дата: 01.05.07 09:31
Оценка:
Здравствуйте, Onizuka.
а ты ключи в таблицах DataSet нумируй в отрицательную сторону тогда они не будут пересикатся с теми которые уже есть в базе данных.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Re[4]: Странный эффект DataSet функция Merge
От: Onizuka  
Дата: 02.05.07 07:25
Оценка:
Здравствуйте, Дьяченко Александр, Вы писали:

ДА>Здравствуйте, Onizuka.

ДА>а ты ключи в таблицах DataSet нумируй в отрицательную сторону тогда они не будут пересикатся с теми которые уже есть в базе данных.

Александр спасибо, так и делаю, На сет предыдущего своего высказывания — признаюсь был не прав(Если довавить строку а потом ее изменить предварительно не сделав AcceptChanges() состояние строки все равно остается DataRowState = Added).
Все равно остается вопрос, это единственный вариант — Добавить строки в исходный датасет, получить датасет изменений с помощью GetChanges(), синхронизировать датасет изменений с базой данных, проверить чтобы он после синхронизации не содержал ошибок, обойти свой исходный датасет и удалить из него все строки со значением Added и смерджить(Merge) исходный датасет с синхронизированым???
Не знаю почему, этот вариант не вызывает у меня симпатии, подсознательно чувствую его ненадежность чтоли.
Если есть какие нить более красивые варианты работы с добавление данных в датасет и последующей его синхронизации с базой данных расскажите пожалуйста.
Re[5]: Странный эффект DataSet функция Merge
От: Дьяченко Александр Россия  
Дата: 02.05.07 11:18
Оценка:
Здравствуйте, Onizuka, Вы писали:

ДА>>Здравствуйте, Onizuka.

ДА>>а ты ключи в таблицах DataSet нумируй в отрицательную сторону тогда они не будут пересикатся с теми которые уже есть в базе данных.
O>Александр спасибо, так и делаю, На сет предыдущего своего высказывания — признаюсь был не прав(Если довавить строку а потом ее изменить предварительно не сделав AcceptChanges() состояние строки все равно остается DataRowState = Added).
O>Все равно остается вопрос, это единственный вариант — Добавить строки в исходный датасет, получить датасет изменений с помощью GetChanges(), синхронизировать датасет изменений с базой данных, проверить чтобы он после синхронизации не содержал ошибок, обойти свой исходный датасет и удалить из него все строки со значением Added и смерджить(Merge) исходный датасет с синхронизированым???
O>Не знаю почему, этот вариант не вызывает у меня симпатии, подсознательно чувствую его ненадежность чтоли.
O>Если есть какие нить более красивые варианты работы с добавление данных в датасет и последующей его синхронизации с базой данных расскажите пожалуйста.

В свое ремя я свой merge делал, правда упор там был на возмозность слияния на уровне полей, а не на уровне записей. Проблему с новыми записями вроде тоже решал, но найти исходников что-то не могу (искал еще когда первый ответ писал), ну а с ходу что-то не выдумывается ничего, разве что попробывать на OnUpdate/OnInsert или как оно там называется пошаманить что нить, но что из этого выйде хз.
... << RSDN@Home 1.2.0 alpha rev. 677>>
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.