DataSet - Update - как получить ID из базы при синхронизации
Я только разбираюсь с ADO.NET, так что заранее прошу прощения, если мой вопрос покажется вам излишне простым и не заслуживающим ответа.
Имеется таблица Access, имеется многотабличный DataSet. Нужно организовать обновление в базу новых полей из датасет так, чтобы в датасет записывались генерируемые базой первичные ключи.
Инкремент ключа в ДатаСет в клиенте:
.AutoIncrementSeed = -1
.AutoIncrementStep = -1
Где-то в интернетах многие советует инкрементировать первичный ключ для новых полей в локальном ДатаСет отрицательным значением, чтобы при обновлении получить правильный ключ. Так вот вопрос: как его получить? С базой работаю через OdbcDataAdapter, если это важно.
Есть вариант с тем, чтобы после каждого обновления, обращаться к базе с запросом вроде "select max(id)...", но мне кажется, это не очень правильно.
Извиняюсь за сумбурность (не спал сутки).
P.S. Вы, это... завязывайте рефлексировать. Надо задать вопрос - задавайте. Не уверены, что вопрос не тупой? Ну так какая разница, тут ведь как: если ответ ищется в МСДН за пять минут, так и ответят. А если не ищется, то может быть ответят по существу. Форум ведь для того и придуман, чтобы вопросы спрашивать.;)
"ADO.NET Сборник рецептов. Для профессионалов"
Автор: Билл Гамильтон
Год: 2005
Издательство: Питер
Думаю, тебе она поможет.
Чтобы найти последнее значение, использованное для столбца с автоматическим шагом, можно воспользоваться инструкцией SELECT IDENTITY. Название таблицы задать нельзя. Будет получено значение из последней обновленной таблицы, содержащей столбец с автоматическим шагом.
т.е. если будет работать один клиент, то можно в пределах транзакции узнать последний ID в таблице. Если будет их много, то лучше формировать на клиенте.
Буду думать дальше. Проблема в том, что я не могу формировать ключи в клиенте, так как тогда нет никаких гарантий, что они будут соответствовать тому, что сгенерировала база. База одна, а клиентов много. Вопрос состоял в том, возможно ли, чтобы DataSet получал сгенерированные базой ключи при апдейте (если нет, то к чему тогда инкрементировать первичный ключ в ДатаСет отрицательным значением) .
Сейчас остановился на варианте, чтобы перед обновлением получать максимально возможный ID из базы и явно его указывать при обновлении (есть одна "главная" таблица, и несколько зависимых от нее).
Буду думать дальше. Проблема в том, что я не могу формировать ключи в клиенте, так как тогда нет никаких гарантий, что они будут соответствовать тому, что сгенерировала база. База одна, а клиентов много. Вопрос состоял в том, возможно ли, чтобы DataSet получал сгенерированные базой ключи при апдейте (если нет, то к чему тогда инкрементировать первичный ключ в ДатаСет отрицательным значением) .
Сейчас остановился на варианте, чтобы перед обновлением получать максимально возможный ID из базы и явно его указывать при обновлении (есть одна "главная" таблица, и несколько зависимых от нее).
смотри в строну GUID - гарантия уникальности
его формируешь на клиенте и кидаешь в БД
Как-то не парит, да и таблицы удобнее администрировать с ними, хотя глазками особо не посмотришь в них связи.
З.Ы. Хы, Оксотник, таки, опередил.
Может быть будем внимательней читать, о чем спрашивает топикстартер? Или вы готовы указать версию MS Access в котором есть ХП и SCOPE_IDENTITY()?
А автору я бы посоветовал в первую очередь смотреть в сторону нормальных решений. Использование гуидов само по себе достаточно спорное решение - а если это все еще и на акцессе лепится - это просто ужасно.
Используйте либо макросовтовский экспресс-эдишион - либо куча абсолютно бесплатных решений типа PostrgreSQL, Firebird и пр. - тем более что, к примеру, в рамках проекта Firebird существуют компоненты в том числе и для использования в C#.
какие могут быть "против"?
почему применение гуидов в аксессе ужасно?
какое решение изящней?
В коде это выглядит примерно так:
{
int newID = 0;
OdbcCommand idCMD = new OdbcCommand("SELECT @@IDENTITY", Database.m_OdbcConnection);
if (e.StatementType == StatementType.Insert)
{
//здесь получаем новый ID
newID = (int)idCMD.ExecuteScalar();
//если обновилась ячейка в родительской таблице, обновляем значения в дочерних таблицах
if (e.Row.Table.TableName == "ALBUM")
{
//CHILDTABLE1
DataRow[] rows = dataSet.Tables["CHILDTABLE1"].Select("PARENT_FK = " + e.Row[0].ToString());
foreach (DataRow row in rows)
row["PARENT_FK"] = newID;
//CHILDTABLE2
rows = dataSet.Tables["CHILDTABLE2"].Select("PARENT_FK = " + e.Row[0].ToString());
foreach (DataRow row in rows)
row["PARENT_FK"] = newID;
}
e.Row[0] = newID;
}
}
почему применение гуидов в аксессе ужасно?
какое решение изящней?
блин забыл ответить :)
1. Самое первое - скорость доступа. Второе - размер поля.
2. Использование 16-байтового (шестнадцатибайтового) числа для идентификации записи говорит о непробиваемом оптимизме разработчика.
3. Разделить серверный и локальный идентификатор. Это отчасти нарушение нормализации базы - но вполне допустимое.
2Mr. White честно говоря мне лично не очень понятно - почему не использовать каскадные обновления?