powered by simpleCommunicator - 2.0.60     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Блокировка редактируемых записей
5 сообщений из 5, страница 1 из 1
Блокировка редактируемых записей
    #32225936
duha
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
привет.

можно ли сделать так ( SQL2000 Delphi7 ADO )

в программе в гриде лежит укороченный список полей.
например название товара и тип .

Когда юзер выбирает товар, нажимает кнопку "редактировать",
появляется диалог редактирования для всех полей:
тип, цена, единицы измерения, можно еще фотку в блобе если потребуется итд

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

Я хочу узнать, можно ли, используя SQL и вызовы методов объектов ADO
(например ADOQuery.Edit (?) ), сделать так, чтобы при вызове этой же конструкции другим юзером
у него вылазил exception?

например что-то вроде этого
(может можно без try-except, проверять что-то или функцию вызывать?)

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
procedure Обработчик Кнопки Редактировать :)
begin
     try
         <тут пытаемся сообщить серверу, что хотим редактировать запись>
     except
        ShowMessage('Эту запись изменяет другой юзер');
        exit;
      end;

   //запись в данный момент захвачена для изменения
    создаем окно диалога, а потом, если юзер нажал  "сохранить" ,
    делаем вызов update в query или СП.
   
   освобождаем запись.
end;

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

Нужно ли использовать для этого в окне редактирования
обычные контолы (например Edit, Combobox, Memo) или
туда нужно обязательно ставить DB Controls?

=================================
Можно конечно добавить в таблицу одно или несколько полей,
показывающих факт захвата записи и в нужный момент как бы взводить флажок.
(в простейшем варианте подойдет поле Locked типа бит = 0 или 1),
однако в случае пропажи питания на клиенте в таблице останеться
запись, помеченная как 'редактируемая сейчас'.
Можно ли использовать этот способ вместе с транзакциями,
чтобы избежать таким образом захваченных записей при аварийном завершении приложения
или сбоя Windows на клиенте?
...
Рейтинг: 0 / 0
Блокировка редактируемых записей
    #32226026
nomorenames
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
У меня, созданный с помощью коллективного разума, работает следующий код.
Итак, давай по очереди:
1. Создаем таблицу на SQL сервере
В нее будут кидаться данные об открытой записи. В моем случае уникальный идентификатор записи DOCID varchar, но можно переделать и под другой.
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
if exists (select * from sysobjects where id = object_id(N'[dbo].[DOC_EDITING_STATUS]') and OBJECTPROPERTY(id, N'IsUserTable') =  1 )
drop table [dbo].[DOC_EDITING_STATUS]
GO

CREATE TABLE [dbo].[DOC_EDITING_STATUS] (
	[docid] [nvarchar] ( 10 ) NOT NULL ,
	[spid] [smallint] NOT NULL ,
	[hostname] [nchar] ( 128 ) NOT NULL ,
	[hostprocess] [nchar] ( 8 ) NOT NULL ,
	[loginame] [nchar] ( 128 ) NOT NULL ,
	[login_time] [datetime] NOT NULL 
)
GO


2. Создаем на SQL сервере процедуру, к которой будет обращаться клиентское приложение при любом обращении к таблице, записи в которой надо блокировать
Код: 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.
CREATE PROCEDURE dbo.OPEN_DOC_STATUS_SP
	@docid nvarchar( 10 ), 
	@action tinyint,
	@hostname varchar( 128 ) out,
             @loginame varchar( 128 ) out

 --Процедура отслеживания документов, открытых в режиме редактирования
 
 -- Входные параметры:
 
 --  @docid - идентификатор документа
 
 --  @action - 1-документ открывается; 2- документ закрывается, 3 - документ удаляется
 
 -- Выходные параметры:
 
 --   RETURN -1 Уже открыт, 0 Еще не открыт
 
 --  @hostname - рабочая станция
 
 --  @loginame - имя пользователя
 

AS
  SET NOCOUNT ON
  -- Попытка открытия записи. Если она открыта, то возвращаем -1 и станцию с пользователем
 
  IF @action =  1  BEGIN
    IF EXISTS(SELECT DOC_EDITING_STATUS.*
              FROM DOC_EDITING_STATUS
                   INNER JOIN master..sysprocesses sysproc ON
                   DOC_EDITING_STATUS.spid = sysproc.spid AND
                   DOC_EDITING_STATUS.hostname = sysproc.hostname AND
                   DOC_EDITING_STATUS.hostprocess = sysproc.hostprocess AND
                   DOC_EDITING_STATUS.loginame = sysproc.loginame AND
                   DOC_EDITING_STATUS.login_time = sysproc.login_time
              WHERE DOC_EDITING_STATUS.docid = @docid) BEGIN
	      SELECT 
		@hostname = DOC_EDITING_STATUS.hostname, 
		@loginame = DOC_EDITING_STATUS.loginame
	      FROM DOC_EDITING_STATUS
	      WHERE docid = @docid
	      RETURN(- 1 )   -- запись занята
 
	END
    ELSE BEGIN  -- Открываем запись и вносим данные о ее открытии в табл. DOC_EDITING_STATUS
 
      DELETE DOC_EDITING_STATUS
      WHERE docid = @docid
      INSERT INTO DOC_EDITING_STATUS(docid, spid, hostname, hostprocess, loginame, login_time)
      SELECT @docid,
             sysproc.spid,
             sysproc.hostname,
             sysproc.hostprocess,
             sysproc.loginame,
             sysproc.login_time
      FROM master..sysprocesses sysproc
      WHERE sysproc.spid = @@spid
      RETURN( 0 )   -- запись свободна для открытия и открывается. данные сохраняются в табл DOC_EDITING_STATUS
 
    END
  END

 -- запись очищается только тем процессом который ее открыл
 
  IF @action =  2  BEGIN  -- Закрытие записи и удаление информации о ней
 
    DELETE DOC_EDITING_STATUS
    WHERE docid = @docid AND
          spid = @@spid
    RETURN( 0 )
  END

 --  -- Попытка удаления записи. Если она открыта, то возвращаем -1 и станцию с пользователем
 
  IF @action =  3  BEGIN
    IF EXISTS(SELECT DOC_EDITING_STATUS.*
              FROM DOC_EDITING_STATUS
                   INNER JOIN master..sysprocesses sysproc ON
                   DOC_EDITING_STATUS.spid = sysproc.spid AND
                   DOC_EDITING_STATUS.hostname = sysproc.hostname AND
                   DOC_EDITING_STATUS.hostprocess = sysproc.hostprocess AND
                   DOC_EDITING_STATUS.loginame = sysproc.loginame AND
                   DOC_EDITING_STATUS.login_time = sysproc.login_time
              WHERE DOC_EDITING_STATUS.docid = @docid) BEGIN
	      SELECT 
		@hostname = DOC_EDITING_STATUS.hostname,
             		@loginame = DOC_EDITING_STATUS.loginame
       	     FROM DOC_EDITING_STATUS
      	     WHERE docid = @docid
      	     RETURN(- 1 )  -- запись занята
 
    	END
    ELSE BEGIN
      DELETE DOC_EDITING_STATUS
      WHERE docid = @docid AND
          spid = @@spid
      RETURN( 0 )
    END
  END
  
  SET NOCOUNT OFF
RETURN( 0 )


3. Дельфийская процедура, которая открывает запись с проверкой ее статуса.

Код: 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.
procedure TForm1.acPropertiesExecute(Sender: TObject);
var
  S, Str: String;
  ADOStoredProc: TADOStoredProc;
begin
  if DBGridEh1.DataSource = nil then Exit;
{Определение номера документа и проверка статуса доступности заявления}
  S:=  {ТВОЙ УНИКАЛЬНЫЙ ИДЕНТИФИКАТОР ЗАПИСИ (надо поймать самому)};

{Проверка, открыта ли запись другим пользователем. Процедура выполняется на сервере
возвращает - 1 , если запись редактируется, станцию и  редактирующего юзера}
  ADOStoredProc:= TADOStoredProc.Create(nil);
  try
    ADOStoredProc.Connection := SQL.SQL_Data;
    ADOStoredProc.ProcedureName := 'OPEN_DOC_STATUS_SP';
    ADOStoredProc.Parameters.Refresh;
    ADOStoredProc.Parameters[ 1 ].Value := S;
    ADOStoredProc.Parameters[ 2 ].Value :=  1 ; // Документ открывается
    ADOStoredProc.Parameters[ 3 ].Value := ''; // рабочая станция
    ADOStoredProc.Parameters[ 4 ].Value := ''; // пользователь
    ADOStoredProc.ExecProc;
    if ADOStoredProc.Parameters[ 0 ].Value = - 1  then begin  //Запись УЖЕ открыта
      Str:='Заявление: ' + # 9  + S + # 10  +
        'Запись открыта пользователем ' + QuotedStr(UpperCase(ADOStoredProc.Parameters[ 4 ].Value)) +
        ' на рабочей станции ' + QuotedStr(ADOStoredProc.Parameters[ 3 ].Value) + # 10  +
        'в режиме редактирования.' + # 10  +
        'Открыть запись только для чтения?';
      if Application.MessageBox (PChar(Str), 'Предупреждение',
        MB_YESNO + MB_ICONWARNING) = IDYES then begin
...
...
...
      end;
    end
    else begin
       Str:= 'Заявление No.' + S + ' открывается Вами в режиме редактирования' + # 10  +
        'и будет недоступно другим пользователям системы.';
      Application.MessageBox (PChar(Str), 'Предупреждение', MB_OK	+ MB_ICONWARNING);
      // открытие формы заполнения Заявления в режиме редактирования
...
...
...
    end;
    ADOStoredProc.Free;
  except
      ShowMessage('ERROR! Can not save recod about opening document');
  end;
end;


4. Дельфийская процедура закрытия и разблокировки записи
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
procedure TFMigratioCGRP.CloseFDocument(RequestCtrlNum: string);
var
  ADOStoredProc: TADOStoredProc;
begin
// Разблокировка записи, открытой для редактирования
  ADOStoredProc:= TADOStoredProc.Create(nil);
  try
    ADOStoredProc.Connection := SQL.SQL_Data;
    ADOStoredProc.ProcedureName := 'OPEN_DOC_STATUS_SP';
    ADOStoredProc.Parameters.Refresh;
    ADOStoredProc.Parameters[ 1 ].Value := RequestCtrlNum;
    ADOStoredProc.Parameters[ 2 ].Value :=  2 ; // Документ закрывается
    ADOStoredProc.Parameters[ 3 ].Value := ''; // рабочая станция
    ADOStoredProc.Parameters[ 4 ].Value := ''; // пользователь
    ADOStoredProc.ExecProc;
  except
    ShowMessage('ERROR! Can not save record about free document.');
  end;
  ADOStoredProc.Free;
end;



5. Пиво, с благодарностью за идею передашь pkarklin, который обитает здесь и в SQL
...
Рейтинг: 0 / 0
Блокировка редактируемых записей
    #32226198
duha
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
ЗдОрово!
Большое спасибо.
...
Рейтинг: 0 / 0
Блокировка редактируемых записей
    #32226233
nomorenames
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2duha
Большая просьба, Отпиши о работоспособности на SQL2000.
Я это опробовал на семерке, а будет необходимость переводить на 2000.
...
Рейтинг: 0 / 0
Блокировка редактируемых записей
    #32226302
duha
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
ОК.
...
Рейтинг: 0 / 0
5 сообщений из 5, страница 1 из 1
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Блокировка редактируемых записей
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]