|
|
|
Работа с БД со множеством связей (Access 2000 + ADO.NET)
|
|||
|---|---|---|---|
|
#18+
Расскажу все сначала. Имеется БД в Access ( 24 таблицы, все теблицы имеют ключ - поле с именем ID (Autoincrement), все таблицы связаны друг с другом (каскадное удаление/обновление) ) В приложении (WinForms) я хочу загузить всю БД из файла в DataSet поработать с DataSet'ом и сохранить изменения обратно в файл (структура DataSet'а полностью такая же как и у оригинальной БД - со всеми связями и ключами). БД из файла в ДатаСет гружу следующим образом: открываю соединение, каждая таблица загружается отдельно своим ДатаАдаптером, для каждого ДатаАдаптера создается КоммандБилдер, подписываюсь на RowUpdated Адаптера, чтобы корректировать поле ID, когда таблица будет обновляться обратно в БД ДатаАдаптер сохраняется в хеш-массиве (чтобы использовать его же затем для вызова метода Update() для данной теблицы) закрываю соединение. ДатаСет в БД пытаюсь сохранить следующим образом: открываю соединение, Для всех таблиц: { получаю изменения, внесенные в Датасет отыскиваю в хеш-массиве по имени таблицы нужный ДатаАдаптер, вызываю Update() найденного Адаптера, } закрываю соединение. Проблема: например, при добавлении трех записей в еще пустую таблицу ДатаСета он генерирует для записей следующие ID: 0 1 2 Пытаюсь передать изменения в Аксесс. Передается первая строка, но Аксесс сам для нее сгенерирует ID, равное 1 (а не 0, как до этого сгенерировал ДатаСет). Пытаюсь вернуть ID, сгенерированное Аксессом в Датасет (в обработчике события RowUpdated() запрашивается @@IDENTITY): Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. args.Row["ID"] = newID; генерируется исключение, т.к. в ДатаСете уже существует поле ID со значением 1 Собственно вопрос : как с этим бороться????? Сам подход для работы с БД верно выбран??? (то, что я загружаю в ДатаСет ВСЮ БД??? то, что БД загружается отдельно по табличкам???) Класс для работы с Датасетом приведен ниже (здесь грузятся не все таблицы из БД, а только четыре). Для доступа к ДатаСету нужно из программы обратится к полю CDBMan.Instance.dstbData - если ДатаСет уже заполнен, то получаем ссылку на него, если еще не заполнен, то создается новый и заполняется. Для записи изменений обратно в БД - метод CDBMan.vUpdate() Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. 71. 72. 73. 74. 75. 76. 77. 78. 79. 80. 81. 82. 83. 84. 85. 86. 87. 88. 89. 90. 91. 92. 93. 94. 95. 96. 97. 98. 99. 100. 101. 102. 103. 104. 105. 106. 107. 108. 109. 110. 111. 112. 113. 114. 115. 116. 117. 118. 119. 120. 121. 122. 123. 124. 125. 126. 127. 128. 129. 130. 131. 132. 133. 134. 135. 136. 137. 138. 139. 140. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 06.09.2005, 14:10 |
|
||
|
Работа с БД со множеством связей (Access 2000 + ADO.NET)
|
|||
|---|---|---|---|
|
#18+
Весь пост не осилил. :) Возможно вам поможет такое решение: В таблицах датасета настраиваете автоинкремент с 0-я и с пририщением в -1. На связях между таблицами датасета настраиваете каскадные обновления. После сохранения родительской таблицы в БД оттуда считывается сохраненная строка целиком (включая новый, сгенерированный акцессом, первичный ключ). По каскаду новый валидный первичный ключ обновляет подчиненные записи в других таблицах. Потом можно и их сохранять в бд. Вот как то так. зы: прием не мой, вычитал в книжке сеппы. наверняка можно найти в инете более подробное описание. ззы: если не правильно понял вопрос, то сорри :) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 06.09.2005, 14:45 |
|
||
|
Работа с БД со множеством связей (Access 2000 + ADO.NET)
|
|||
|---|---|---|---|
|
#18+
А почему используете CommandBuilder ? Не хочется самому писать адаптеры? Лучше бы написать свой адаптер для вставки и обновления. Если у вас поле ID в Access типа(Identity), то не нужно будет передавать значение этого поля в БД из DataSet при добавлении новой записи. Тогда проблемы не будет как таковой. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 06.09.2005, 15:03 |
|
||
|
Работа с БД со множеством связей (Access 2000 + ADO.NET)
|
|||
|---|---|---|---|
|
#18+
Артем1 Возможно вам поможет такое решение: В таблицах датасета настраиваете автоинкремент с 0-я и с пририщением в -1. На связях между таблицами датасета настраиваете каскадные обновления. После сохранения родительской таблицы в БД оттуда считывается сохраненная строка целиком (включая новый, сгенерированный акцессом, первичный ключ). По каскаду новый валидный первичный ключ обновляет подчиненные записи в других таблицах. Потом можно и их сохранять в бд. Вот как то так. Действительно так дожно работать. Красиво придумано. Спасибо за ответ. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 06.09.2005, 15:16 |
|
||
|
Работа с БД со множеством связей (Access 2000 + ADO.NET)
|
|||
|---|---|---|---|
|
#18+
Alex_2003А почему используете CommandBuilder ? Не хочется самому писать адаптеры? Лучше бы написать свой адаптер для вставки и обновления. Если у вас поле ID в Access типа(Identity), то не нужно будет передавать значение этого поля в БД из DataSet при добавлении новой записи. Тогда проблемы не будет как таковой. К сожалению в моем случае так проблему решить не получиться. Если я оставляю назначение ID на усмотрение Аксесса и не буду возвращать его обратно в ДатаСет, то при обновлении вначале родительской таблицы, а затем дочерней, у дочерней foreign key'и все поедут (ведь primary key'и в родительской таблице Аксесс поизменял, а в дочерних остались старые значения). Если бы связей не было, то таких проблем и не возникло бы. Все же спасибо за ответ. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 06.09.2005, 15:24 |
|
||
|
Работа с БД со множеством связей (Access 2000 + ADO.NET)
|
|||
|---|---|---|---|
|
#18+
Да,с Access я давно не работал. У меня БД SQL Server, там решение проще получается, т.к. есть замечательная функция SCOPE_IDENTITY(), которая возвращает новый ID в ХП, функции или пакете. Но в Access тоже можно сделать след. образом: Для адаптера ( InsertCommand ) пишете что-то вроде: "INSRET INTO tablename(...) values(...); SELECT * FROM tablename WHERE ID = (SELECT max(ID) FROM tablename)" Тогда после добавления ACCESS Вам вернет новый ID. И в Датасет Вы получите то что нужно. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 06.09.2005, 16:49 |
|
||
|
Работа с БД со множеством связей (Access 2000 + ADO.NET)
|
|||
|---|---|---|---|
|
#18+
А Вы Relation'ы настройте и будет Вам счастье с автоматическим обновлением foreign ключей. ADO.NET в отличие от старого АДО с идентити полями отлично умеет работать ! ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 08.09.2005, 11:28 |
|
||
|
Работа с БД со множеством связей (Access 2000 + ADO.NET)
|
|||
|---|---|---|---|
|
#18+
Проблему решил следующим образом: настроил в DataSet'е для полей ID отрицательное автоприращение. Dataset генерирует для новых строк отрицательные ID. Теперь при передаче добавленных строк обратно в Access, он сам генерирует ID для новых строк (положительное значение). Спрашиваю у Access'а новый ID и отдаю его обратно Dataset'у, тот уже обновляет у себя все внешние ключи в дочерних таблицах (по Relations). ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 08.09.2005, 12:00 |
|
||
|
|

start [/forum/topic.php?fid=17&fpage=116&tid=1353626]: |
0ms |
get settings: |
6ms |
get forum list: |
11ms |
check forum access: |
2ms |
check topic access: |
2ms |
track hit: |
39ms |
get topic data: |
9ms |
get forum data: |
2ms |
get page messages: |
32ms |
get tp. blocked users: |
2ms |
| others: | 215ms |
| total: | 320ms |

| 0 / 0 |
