Применение tagged values в БД
Применение стандартных методов проектирования баз данных не всегда удовлетворяет запросы программиста. Одно из ограничений – невозможность изменить набор атрибутов объекта после создания БД, что, при постоянно изменяемых требованиях заказчика, приводит к необходимости менять структуру БД (не потеряв при этом введенные данные), менять и заново отлаживать код программы, поля ввода/редактирования и т.д.
Вашему вниманию предлагается один из способов решения этой проблемы — применение tagged values (TV , тэг-значений, или именованных значений).
Сами значения хранятся в БД в строковом формате, но могут интерпретироваться в приложении по-разному, в зависимости от заданного типа значения. Аналог – всем известные ini-files! Основное преимущество применения TV – это возможность расширения списка значений в процессе исполнения приложения, без изменения структуры БД!
(image placeholder)
Список тэг-значений хранятся в таблице TaggedValue.
- DefaultValue – это значение будет использоваться, если не задано действующее значение.
- DefaultValueAlias – соответственно, значение для локализации.
- ValueType – тип значения. Кроме стандартных типов, можно использовать свои, все зависит от фантазии разработчика. В зависимости от типа значения выбирается встроенный редактор значений. Например, для типа «OCL» используется редактор OCL-выражений. Для перечислимого типа производится выбор значений, которые хранятся в таблице TV_ValueSet. Возможен выбор из списка объектов БД – тогда надо задать ValuesListName.
- Hint – подсказка при выборе/редактировании значения.
- HintAlias – локализованная подсказка.
- IsReadOnly – ну, это понятно.
- ValuesListName – название класса объектов, из списка значений которых будет производиться выбор. Например «City», и тогда будет предложен выбор из списка ClassByExpressionName(‘City’).
Список значений для набора объектов – в таблице TV_ValueSet. Например, для логического типа можно задать значения «True/False», а возможно и «Можно/Нельзя».
Сами значения TV хранятся в таблице TV_Value. StringValue – действительное значение, значение, StringValueAlias – то, которое используется для локализации программы (или для показа юзеру ().
(image placeholder)
Для того, чтобы подключить к объекту тэг-значения, нужно создать ассоциацию типа n-n – OverridenTagedValues. Вся прелесть в том, что таким образом хранятся только переопределенные значения! Если нет значения – будет использоваться значение по-умолчанию! Классом такой ассоциации будет TV_Value, то есть, экземпляр класса – тэг-значение будет создан только при действительном вводе информации! Если грамотно подобрать умолчания, можно существенно сэкономить на размере БД!
Программная реализация.
Эта функция возвращает действующее тэг-значение по его имени. Если значение не было переопределено – возвращается значение по умолчанию.
function TMetaActorProperty.ActualValueByName(Tag: String): String;
var
_TaggedValue:TTaggedValue;
_TV_Value:TTV_Value;
begin
_TaggedValue:=Self.TaggedValues.EvaluateExpressionAsDirectElement(‘self->select(name=’+QuotedStr(Tag)+’)->first’) as TTaggedValue;
if Self.OverridenTaggedValues.Includes(_TaggedValue) then begin
_TV_Value:=Self.TV_Value.BoldObjects[Self.OverridenTaggedValues.IndexOf(_TaggedValue)];
Result:=_TV_Value.StringValue;
end
else
Result:=Self.TaggedValues.EvaluateExpressionAsString(‘self->select(name=’+QuotedStr(Tag)+’)->first.defaultValue’, 1);
end;
Эта процедура устанавливает тэг-значение.
procedure TMetaActorProperty.SetTVByName(Tag: String; Value: String);
var
_TaggedValue:TTaggedValue;
_TV_Value:TTV_Value;
Overriden: Boolean;
begin
_TaggedValue:=LocateInList(Self.TaggedValues, ‘name’, Tag) as TTaggedValue;
if not Assigned(_TaggedValue) then begin
MsgError(Self.Name+’: Not found TV=’+Tag);
Exit;
end;
Overriden:=Self.OverridenTaggedValues.Includes(_TaggedValue);
if Overriden then begin //Ранее было переопределено
_TV_Value:= //Найдем переопределенное значение
Self.TV_Value.BoldObjects[Self.OverridenTaggedValues.IndexOf(_TaggedValue)];
if (Value=_TaggedValue.DefaultValue) then //Если ввели значение по умолчанию — удалим переопределенное
Self.OverridenTaggedValues.Remove(_TaggedValue)
else //Ранее было переопределено и изменили значение
_TV_Value.StringValue:=Value;
end
else //Ранее было по умолчанию
begin
Assert(Assigned(_TaggedValue), ‘SetTVByName’);
Self.OverridenTaggedValues.Add(_TaggedValue);
_TV_Value:= //Найдем переопределенное значение
Self.TV_Value.BoldObjects[Self.OverridenTaggedValues.IndexOf(_TaggedValue)];
_TV_Value.StringValue:=Value;
end;
end;
Функция дает список подключенных тэг-значений.
function TMetaActorProperty.TaggedValues: TTaggedValueList; //Find TaggedValueList
var
expr: string;
begin
Result:=nil;
if not Assigned(Self) then Exit;
expr:=’TV_Section.allInstances->select(name=’+QuotedStr(Self.MetaClassName)+’)->first.taggedValues’;
Result:=TBoldSystem.DefaultSystem.EvaluateExpressionAsDirectElement(expr)as TTaggedValueList;
end;
Такие тэг-значения удобны для сохранения в БД настроек программы, быстрого создания прототипов проекта для согласования с заказчиком и добавления/изменения атрибутов на «лету» (в дальнейшем, после обкатки приложения, легко все оформить в виде «настоящих» атрибутов).
Для создания/редактирования тэг-значений применяется редактор на основе компонента TCommonInspector из пакета Greatis — http://www.greatis.com.
Ответить
Хотите присоединиться к обсуждению?Не стесняйтесь вносить свой вклад!