linq-to-sql параллелизм пользователя - PullRequest
2 голосов
/ 25 февраля 2010

В настоящее время я работаю над формой окон C # с linq-to-sql, которая выбирает строку из таблицы SQL, а затем позволяет пользователю редактировать поля в этой строке. Эта форма будет одновременно использоваться несколькими пользователями, и мне бы хотелось, чтобы она была такой, когда кто-то выбрал строку и в настоящее время вводит данные в форму (с помощью которой строка будет обновляться, когда пользователь нажимает кнопку в форме). ) никто другой не может выбрать эту строку. Как только пользователь нажмет кнопку, чтобы выполнить запрос на обновление, обновленную строку снова можно будет выбрать. По сути, этот процесс:

пользователь выбирает строку -> строка становится недоступной для выбора другими пользователями -> пользователь изменяет значения полей строки -> пользователь отправляет и обновления строки -> строка снова становится доступной для выбора.

Существует ли какая-либо существующая функциональность, которую я могу использовать для достижения этой цели, или мне нужно будет создать таблицу, которая отслеживает, какие строки не могут быть выбраны, и запрашивает у приложения эту таблицу перед выбором строк (т. Е. Таблица запросов, чтобы увидеть, недоступна ли строка , если не вставлять rowid, пользователь редактирует, то удалить строку после того, как пользователь отправил изменения)?

Ответы [ 3 ]

4 голосов
/ 25 февраля 2010

То, что вы пытаетесь сделать, - это обеспечить неоптимистичный параллелизм для ресурсов, к которым вы обращаетесь (в данном случае, к строкам базы данных).

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

При этом вам, вероятно, следует взглянуть на оптимистическую модель параллелизма, где у вас есть какая-то временная метка (будь то двоичное значение или дата, то, что меняется с каждым обновлением записи), которая сравнивается, когда Вы хотите выполнить операцию обновления.

Если идентификатор и отметка времени совпадают, операция завершается успешно, в противном случае она информирует пользователя, что кто-то еще обновил запись, и должна перезагрузить данные и попытаться обновить запись еще раз.

Следует отметить, что эта модель масштабируется намного лучше, чем любые неоптимистичные модели.

При этом, если вы действительно хотите неоптимистичную модель, вы должны подделать ее.

Как упоминалось выше, модели поставщиков данных .NET не поддерживают неоптимистичный параллелизм. Когда пользователь начинает операцию, он проверяет поле («заблокировано» или что-то в этом роде), чтобы увидеть, заблокирована ли запись в данный момент. Если он заблокирован, вы не разрешаете пользователю открывать форму для изменения данных. Если он НЕ заблокирован, вы разрешаете пользователю открывать форму и изменять данные.

Есть две важные вещи, которые вы должны сделать здесь. Во-первых, установите для «заблокированного» поля значение true, чтобы указать, что у вас есть блокировка.

Второе - убедиться, что вы работаете в транзакции при сравнении значения и обновлении заблокированного поля. Если вы этого не сделаете, существует возможность одновременного обновления поля двумя клиентами, а вы этого не хотите.

Лучший способ инкапсулировать это - иметь хранимую процедуру, которая принимает идентификатор записи, которую вы хотите заблокировать.

Затем выполняется обновление, например:

--- Update the table.
update <table> set locked = 1 where id = @id and locked = 0

--- Return the rowcount.
return @@rowcount

Следует отметить, что проверка в «заблокированном» поле очень важна, так как позволяет значению @@ rowcount быть либо 0, либо ненулевым (в зависимости от того, используются ли ваши идентификаторы или нет). являются уникальными), которые можно оценить как ложные в нулевом регистре и истинные в ненулевом регистре в коде приложения.

Затем в коде приложения вы завершаете транзакцию, и если значение равно true, вы открываете форму и позволяете пользователю редактировать, в противном случае вы сообщаете ему, что ему нужно подождать.

Когда пользователь завершает сохранение записи, он снова устанавливает бит «заблокирован» в ноль, опять же, в транзакции с другими операциями сохранения.

Единственным явным недостатком этого факта является то, что если ваше приложение падает после того, как пользователь заблокировал запись, оно никогда не станет разблокированным, и вам придется вручную перейти и удалить «заблокированный» бит.

С транзакциями и оптимистичным параллелизмом вам не нужно беспокоиться об этом, поэтому я бы еще раз настоятельно рекомендовал вам не использовать неоптимистическую модель параллелизма.

3 голосов
/ 25 февраля 2010

В Linq to sql есть несколько различных вариантов параллелизма, но не так, как вы описали. При обработке сохранения вы можете установить RefereshMode в KeepCurrentValues, OverwriteCurrentValues, KeepChanges или установить параметры на уровне поля с атрибутом [UpdateCheck] в значение Never, Always, WhenChanged.

Вам потребуется написать собственный код для блокировки записей, на которые вы ссылаетесь. Другим вариантом может быть попытка сохранить запись, перехватить любые исключения параллелизма и спросить пользователя, что он хотел бы сделать (таким образом, установив режим обновления, указанный выше).

1 голос
/ 25 февраля 2010

По умолчанию LINQ-To-SQL обрабатывает параллелизм самостоятельно. Когда данные обновляются обратно в базу данных, LINQ-To-SQL проверит исходные значения по текущим значениям в базе данных. Если исходные значения, выбранные LINQ-To-SQL, отличаются от текущих значений в базе данных, обновление завершится неудачно, сообщая об обновлении данных другим способом. О «текайдо» говорили разные варианты.

Метод SubmitChanges DataContext выдает ChangeConflictException, если строка была изменена после того, как LINQ-To-SQL извлек строку.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...