Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.116.239.195] |
|
Сообщ.
#1
,
|
|
|
День добрый!
Вопрос - как уважаемые господа поступают, когда требуется многопользовательская работа с базой? В частности, как строить поведение проги, дабы юзер имел актуальную информацию и ошибочно не затирал данные, которые успели уже изменить другие юзеры? |
Сообщ.
#2
,
|
|
|
Привет
Для начала, думаю, необходимо определиться с выбором базы. По своему опыту скажу - Access сразу отпадает. Ну, а вопрос по поводу "актуальности" данных, весьма деликатен... В любом случае, данные, которые отображаются юзеру на основании запроса "SELECT" - это "снимок", сделанный в момент запроса. Ну, а чтобы никто не мог изменить данные во время редактирования их другим пользователем существует понятие блокировок. Транзакции - тоже очень полезная штука. Ну, и на последок, я думаю что нужно как можно больше "нагружать" базу данных, т.е. переносить логику в хранимые процедуры... Вот такие общие соображения |
Сообщ.
#3
,
|
|
|
Цитата Miha_Dnepr @ Транзакции - тоже очень полезная штука. Ну, и на последок, я думаю что нужно как можно больше "нагружать" базу данных, т.е. переносить логику в хранимые процедуры... Вот такие общие соображения База, в отличие от сервера приложений, довольно плохо масштабируется, поэтому "нагружать" ее можно только если сервер размером с холодильник, а пользователей планируется мало. В остальных случаях базу грузить зло. Что касается вопроса. Существует такая волшебная вещь, как евенты базы. Она может оповещать слушателей об изменениях в таблице. Копать туда. Если работать через DataSet/DataAdapter, то можно определять, что делать с измененными данными, которые были уже изменены другими пользователями. |
Сообщ.
#4
,
|
|
|
Ну, да, с "больше нагружать" я погарячился, имелось ввиду нажождение "золотой середины" в использовании хранимых процедур и нагрузке сервера приложений.
По-поводу евентов, вопрос интересный... вот, например, меня недавно просвятили, что злополучный Access умудряется выплюнуть событие прежде чем данные реально изменятся. (Я имею ввиду событие DataAdapter.RowUpdated) |
Сообщ.
#5
,
|
|
|
Евенты это очень интересно! Буду балгодарен за пинок в нужном направлении.
СУБД SQL Server 2005. |
Сообщ.
#6
,
|
|
|
Ап.
Прболема вернулась, а про евенты базы так ничего и не нашёл |
Сообщ.
#7
,
|
|
|
Цитата wdk @ Прболема вернулась, а про евенты базы так ничего и не нашёл см. Notification Service у SQL Server сам не работал, но точно знаю, что евенты он генерит Ты пишешь про перезатирания данных, это нормально и это не самая большая проблема при многопользовательском доступе какая может быть. Ее решить можно транзакциями, в частности выбором нужного уровня изоляции. Посмотри на перечисление IsolationLevel элемент которого передается методу BeginTransaction. Более сложные случае решаются путем обработки соответствующих исключений. Например если ты продал билет, а при попытке сохранить изменения об этом узнаешь, что билет продан кем то другим, то обработав соответствующие исключение ты сможешь уведомить об этом пользователя программы в дружественной форме. |
Сообщ.
#8
,
|
|
|
Цитата wdk @ дабы юзер имел актуальную информацию и ошибочно не затирал данные, которые успели уже изменить другие юзеры? Оптимистические блокировки: В таблице ведется учет, когда запись изменена, или вводится понятие версии записи. При выполнении обновления данных если дата или версия не совпадают с вычитанными - выдавать пользователю сообщение: Данные изменились, перезагрузи. Как это оформить - вопрос архитектуры. 2. При выполнении запроса по Update записи, проверять в WHERE не только соответствие первичного ключа, а всех полей, тогда обновление просто не выполнится |
Сообщ.
#9
,
|
|
|
2 идея интересно!
Осталось придумать, как заставить SqlCommandBuilder генерить именно такой запрос. Форма универсальная, ручками запрос написать не получится. Добавлено Хм. Прочитал в МСДН: Цитата Optimistic Concurrency Model for Updates and Deletes The logic for generating commands automatically for UPDATE and DELETE statements is based on optimistic concurrency--that is, records are not locked for editing and can be modified by other users or processes at any time. Because a record could have been modified after it was returned from the SELECT statement, but before the UPDATE or DELETE statement is issued, the automatically generated UPDATE or DELETE statement contains a WHERE clause, specifying that a row is only updated if it contains all original values and has not been deleted from the data source. This is done to avoid new data being overwritten. Where an automatically generated update attempts to update a row that has been deleted or that does not contain the original values found in the DataSet, the command does not affect any records and a DBConcurrencyException is thrown. If you want the UPDATE or DELETE to complete regardless of original values, you must explicitly set the UpdateCommand for the DataAdapter and not rely on automatic command generation. Неправда же, затирает он изменения при adapter.Update! Добавлено SqlCommandBuilder cb = new SqlCommandBuilder(adapter); cb.ConflictOption = ConflictOption.CompareAllSearchableValues; Всё равно в WHERE запроса только ID :/ Добавлено Я в тупике. Вот код, заполняющий датасет ds = new DataSet(); SqlConnection conn = new SqlConnection(connString); adapter = new SqlDataAdapter("SELECT * FROM " + TableName + " ORDER BY ID", conn); adapter.Fill(ds, TableName); SqlCommandBuilder cb = new SqlCommandBuilder(adapter); cb.ConflictOption = ConflictOption.CompareAllSearchableValues; adapter.UpdateCommand = cb.GetUpdateCommand(); adapter.DeleteCommand = cb.GetDeleteCommand(); bsMain.DataSource = ds.Tables[TableName]; //binding source dgvMain.DataSource = bsMain; //datagrid conn.Close(); Где я проганл? |
Сообщ.
#10
,
|
|
|
wdk, я давно не пользовался мастерами и билдерами, но в 1.1 мастер генерил DataAdapter так как я рассказал в 2
|
Сообщ.
#11
,
|
|
|
Попробовал сгенерить мастером, то же самое.
|
Сообщ.
#12
,
|
|
|
Хм.
Почему-то билдер не включает поля в WHERE, если они имеют тип varchar или nvarchar. С char(255), допустим, всё нормально. Но мне-то нужны нормальные строки, без кучи пробелов. |
Сообщ.
#13
,
|
|
|
wdk, попробуй добавить к таблице поле timestamp и использовать CompareRowVersion.
|
Сообщ.
#14
,
|
|
|
Это понятно. Очень желательно по задаче набор полей не менять.. Непонятно, что за странная фигня с полем varchar?
|
Сообщ.
#15
,
|
|
|
Я помню на сайте ASPNETWorld.Ru хорошие статьи на тему ADO.NET были.
Про ADO.NET кажется здесь http://www.aspnetworld.ru/Articles/Category/4.html Там как раз обсуждалась многопользовательская работа. |