powered by simpleCommunicator - 2.0.49     © 2025 Programmizd 02
Форумы / Caché, Ensemble, DeepSee, MiniM, IRIS, GT.M [игнор отключен] [закрыт для гостей] / Модификация свойств
6 сообщений из 6, страница 1 из 1
Модификация свойств
    #33205569
Mr N
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Добрый день.
Возникла необходимость вести историю изменения свойств хранимого объекта. Как можно получить список всех свойст объекта, и определить какие из свойств были модифицированы ?
...
Рейтинг: 0 / 0
Модификация свойств
    #33205656
VadimF
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Посмотрите интерфейс Dictionary для работы с метаданными Cache' :
Class Definition Classes

Вадим
...
Рейтинг: 0 / 0
Модификация свойств
    #33221620
Mr N
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Класс %Dictionary.ClassDefinition позволяет получить только список свойст, а как узнать какие из них были модифицированы ?
...
Рейтинг: 0 / 0
Модификация свойств
    #33224231
Механизатор из Подмосковья
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
"Версионность" свойств не реализована никак, придётся кое-что делать руками.

Один объект физического (а не "программного") мира может иметь только
ОДИН набор атрибутов, считающихся "САМЫМИ СВЕЖИМИ" на данный момент
времени. И в то же время он должен иметь историю изменения этих атрибутов.

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

В первом (пусть у него будет имя propHist) будет идти "накопление версий"
записей при смене хотя бы одного из версионных свойств. Даже если
некоторое св-во сначала поменялось с "A" на "Б", а затем обратно с "Б" на "А"
-- всё равно добавляем НОВЫЕ строки: уникальность двух строк в любом
классе - наследнике %Persistent даже при полном равенстве всех столбцов
обеспечивается в Cache' тем, что он автоматом присваивает им разные
значения в поле ID (и даже если бы этого не было – время проведения этих
изменений всё равно разное).

Во втором классе (propLast) следует хранить ССЫЛКУ на самую последнюю
версию атрибутов, чтобы иметь возможность быстро их пролистывать.

(Начало небольшого лирического отсупления.
Применительно к весьма распространённой складской задаче необходимость
класса propLast «звучит» так: продавцу магазина без разницы, какое
значение имело свойство "Название изделия" или «Производитель» или "Цена
розничная" два дня тому назад; ему надо знать ТЕКУЩИЕ значения. Имхо,
история изменений нужна всего для двух целей:
1) воспроизвести «исторически корректные» значения атрибутов при
повторной распечатке какого-нибудь старого документа;
2) провести аудит с целью выявить нарушителей-злопыхателей, которые хотят
в мутной воде чего-то там наловить
Конец лирического отступления).


Из второго класса (propLast) по вышеуказанной ссылке на первый класс
(propHist) мы сможем вытаскивать всегда "самые свежие" значения атрибутов.

Наконец, в классах, хранящих данные ДОКУМЕНТОВ (docData), должны быть
ссылки на первый класс, но НЕ на "самые свежие" атрибуты, а именно для того
момента времени, когда этот документ создавался.

Т.о., можно сделать примерно так:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
// Накопительный реестр
class propHist Extends %Persistent [ ClassType = persistent, ProcedureBlock ] {
   
 /// нечто, позволяющее однозначно ОТЛИЧАТЬ этот объект 
  /// (напр., какое-то изделие) со всеми его версиями от остальных объектов такого же рода; 
   /// !!! Это _НЕ_ свойство ID, присваиваемое в Cache' автоматически при
добавлении новой строки в таблицу (для классов-наследников %Persistent);
  /// очевидно, значения этого св-ва для ОДНОГО и ТОГО ЖЕ физического объекта (напр., "амортизатора") будут 
 /// в этом реестре ОДИНАКОВЫМИ:
  property someNativeAttr As %???; 

   property versArticul as %String; // первое версионное св-во: артикул
   property versName as %String; // второе верс. св-во: название
   property versPlace as %Float; // третье верс. св-во: место хранения изделия
   // другие верс. свойства
}

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
// Реестр с НЕ-версионными атрибутами и ссылками на "САМЫЕ АКТУАЛЬНЫЕ" атрибуты
class propLast Extends %Persistent [ ClassType = persistent, ProcedureBlock ] {
   property nonVersProp1 as %String;
   property nonVersProp2 as %Float;
   // другие _НЕ_ версионные свойства, НЕ меняющиеся после созд-я объекта

   /// ссылка на ПОСЛЕДНЮЮ  версию набора атрибутов (для поиска на текущий момент времени):
  Property VLast As propHist;
}
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
class docData Extends %Persistent [ ClassType = persistent, ProcedureBlock ] {
  property createUser as %UserList;    // кто создал запись
  property writeUser as %UserList;      // кто изменил запись
  property Qty as %Float,
  property Cost as %Float,
  property updTime as %Timestamp;    // момент изменения
  property V4UpdTime as propHist;   // ссылка на версию НА МОМЕНТ updTime
}

Все SQL-запросы к классам propLast и docData должны, есс-но, включать в
себя JOIN-конструкции по полям propLast.VLast и docData.prop4UpdTime --
тогда мы будем иметь сответственно и "самые свежие" атрибуты, и те их
значения, которые действовали, например, 5 лет назад.

ПРОБЛЕМА в том, что методы, добавляющие новые строки во все эти классы и
обеспечивающие «накопление» версий атрибутов и их нумерацию, а также
ссылку из propLast на propHist запись с самыми актуальными атрибутами – всё
это надо писать самому.

Например, чтобы вытряхнуть список объектов из propLast с самыми АКТУАЛЬНЫМИ атрибутами, пишем:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
Select top  100  
           VLast.versActicul,  -- артикул изделия, САМАЯ АКТУАЛЬНАЯ версия
           VLast.versName,   -- название изделия, САМАЯ АКТУАЛЬНАЯ версия
           Vlast.versPlace,     -- место хранения изделия, САМАЯ АКТУАЛЬНАЯ версия
           nonVersProp1, nonVersProp2
from propLast
where VLast.versActicul %STARTSWITH :var4Articul and  …
order by …
NB: никакого JOIN’a на таблицу propHist НЕ нужно! Свойство-ссылка VLast всё вытащит автоматом.

Чтобы вытащить те версии артикула, названия и места хранения изделия,
которые «действовали» на момент создания некоторого документа (расходной
накладной etc.), надо сделать запрос :
Код: plaintext
1.
2.
Select V4UpdTime.versArticul, V4UpdTime.versName, V4UpdTime.versPlace, Qty,Cost, createUser,writeUser
  From docData
Where ID=…
Здесь снова свойство-ссылка V4UpdTime вытащит из «накопителя» propHist
значения версионных атрибутов именно на то время, когда в документ заносились соотв. записи.

ЗЫ. Текст писал сначала в M$ Word'e, т.к. в "штатной" TEXTAREA этого сайта (да и других тоже) делать это крайне неудобно. Но при переносе сюда через клипборд вылезли странности с форматированием, так что прошу извинить за "корявость стиля".
...
Рейтинг: 0 / 0
Модификация свойств
    #33227190
Mr N
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Большое спасибо Механизатору из Подмосковья за ответ. Но мне не нужно хранить периодические реквизиты, хотелось бы просто знать при сохранении объектов, какие из его свойств были изменены. Смотрел код, в который cache компилирут классы, там используется функция $zobjmod, для того, чтобы узнать был ли модифицирован объект или его свойства, но какие параметры ей передаются понять не смог. Если кто-нибудь знает как работать с этой функцией, расскажите пожалуйста.
...
Рейтинг: 0 / 0
Модификация свойств
    #33237560
Механизатор из Подмосковья
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2Mr N.
Я нашёл кое-что. Может, это и есть то, что ты спрашивал ?

Открываем cache' documatic ( http://home:1972/apps/documatic ), далее лезем в %Library.RegisteredObject и там есть методы:
Код: plaintext
1.
method %IsModified() returns %Integer 
Returns true ( 1 ) if this instance has been modified, otherwise false ( 0 ). 
И еще один:
Код: plaintext
1.
2.
3.
method %ObjectModified() returns %Integer 
This method is somewhat similar to %IsModified but it also checks to see if
swizzled references would cause the object to become modified should they
 be serialized.... (далее много чего еще написано)
Я решил проверить на одном из своих %Persistent-классов и сделал так (в Терминале):
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
s obj1=##class(priceList).%OpenId( 123456 )   w
>obj1=<OBJECT REFERENCE>[ 1 @User.priceList]
w obj1.Name
>ПЕРЕХОДНИК С  220  НА 110В
s obj1.Name="ЛОШАДЬ ПРЖЕВАЛЬСКОГО"  
w obj1.%IsModified()
> 1 
w obj1.%ObjectModified()
> 1 
ЗЫ. Кстати, там есть даже метод, позволяющий УПРАВЛЯТЬ статсом "изменился / не изменился", даже если ты сам изменил какие-то свойства у объекта (!)
Зачем это нужно - не знаю, но метод носит имя:
Код: plaintext
1.
method %SetModified(value As %Integer) returns %Status 
Setting the modified state of the object. 
А еще посмотри полезный метод:
Код: plaintext
1.
2.
method %ValidateObject(force As %Integer =  0 ) returns %Status 
This method performs automatic validation of an object's attribute values. It is 
alled by %Save before persistent objects are stored to the database
...
Рейтинг: 0 / 0
6 сообщений из 6, страница 1 из 1
Форумы / Caché, Ensemble, DeepSee, MiniM, IRIS, GT.M [игнор отключен] [закрыт для гостей] / Модификация свойств
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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