Установка значений атрибутов по умолчанию
Значения по умолчанию, заданные для атрибутов каких-либо классов, используются для автозаполнения соответствующих полей на формах редактирования. Ранее значение по умолчанию для одного из атрибутов было указано при создании диаграммы классов - была указана текущая дата для атрибута “CreateDate” класса “Document”:
Такой синтаксис использутся для указания значения по умолчанию, которое будет использоваться в том случае, если соответствующее поле на форме редактирования не заполнено. Чаще всего такая потребность возникает при создании новой записи, у которой часть полей заполняется таким образом автоматически.
Помимо даты создания документа при создании нового заявления или накладной потребуется также проставлять им уникальный номер и автоматически устанавливать статус “Новый”. Для этого откроем список атрибутов класса “Документ”:
Document → [ПКМ] → ORM: Редактировать свойства → Атрибуты
В открывшейся форме мы можем увидеть заданное по умолчанию значение для атрибута “CreateDate”. Установим следующие свойства для атрибута “Number”:
DefaultValue → 1,
Autoincrement → +,
NotNull → + (обязательно для автоинкремента).
После сохранения свойств атрибута “Number” класс на диаграмме будет иметь следующий вид:
Самостоятельно измените свойства атрибутов следующих классов:
Order
Status ‒ New
Invoice
Status ‒ New
Storehouse
Number ‒ с 1, инкремент
Product
ProductCode ‒ с 1, инкремент
Employee
Number ‒ с 1, инкремент
После выполнения всех описанных выше действий диаграмму классов можно использовать для генерации как фронтенда, так и бэкенда. Не забудьте сохранить её по окончании работы.
Настройка вычислимых атрибутов
Ранее мы также создавали вычислимый атрибут на диаграмме классов ‒ это атрибут “TotalSum” (Стоимость заказа) класса “Order” (Заказ). Он помечен символом “/”:
Для реализации такого атрибута, мы можем добавить ему DataServiceExpression
, но, так как DataServiceExpression
-ы вычисляются не во всех запросах, нам также необходимо реализовать логику этого атрибута в коде.
Чтобы добавить DataServiceExpression
, откройте окно редактирования свойств класса, на против нужного атрибута, в столбце «DataService Expression»
, нажмите кнопку «...»
, в открывшемся окне, можно задать несколько значений для разных типов сервисов данных.
В столбце «DataService»
, нужно указать тип сервиса данных, с которым, будет использоваться SQL
-выражение, в столбце «DataService Expression»
, само SQL
-выражение.
Для атрибута TotalSum
мы можем написать универсальное SQL
-выражение, которое будет работать с любым, SQL
-совместимым, сервисом данных, поэтому, нам достаточно одного выражения, с указанием SQLDataService
в качестве типа сервиса данных.
Остаётся реализовать логику этого атрибута в коде, сами вычисления довольно просты, но если, необходимые для вычисления данные не будут загружены, результат вычислений будет не верный. Поэтому, стоит добавить проверку, что необходимые данные загруженны, и бросить исключение, в противном случае.
/// <summary>
/// TotalSum.
/// </summary>
// *** Start programmer edit section *** (Order.TotalSum CustomAttributes)
// *** End programmer edit section *** (Order.TotalSum CustomAttributes)
[ICSSoft.STORMNET.NotStored()]
[DataServiceExpression(typeof(SQLDataService), "SELECT SUM(PriceWTaxes * Amount) FROM OrderItem WHERE OrderItem.Order_m0 = STORMM" +
"ainObjectKey")]
public virtual double TotalSum
{
get
{
// *** Start programmer edit section *** (Order.TotalSum Get)
if (!CheckLoadedProperty(nameof(OrderItem)))
{
throw new InvalidOperationException($"The '{nameof(OrderItem)}' property not loaded.");
}
double sum = 0;
foreach (OrderItem item in OrderItem)
{
sum += item.PriceWTaxes * item.Amount;
}
return sum;
// *** End programmer edit section *** (Order.TotalSum Get)
}
set
{
// *** Start programmer edit section *** (Order.TotalSum Set)
// *** End programmer edit section *** (Order.TotalSum Set)
}
}
Чтобы обеспечить загрузку необходимых данных, нужно добавить свойства, которые используются в вычислениях, в те представления, в которых присутствует атрибут TotalSum
.
Добавим отдельное представление в класс OrderItem
, со свойствами Amount
и PriceWTaxes
:
Добавим, только что созданное представление, в качестве детейла, в представлении OrderL
класса Order
:
В обоих случаях, мы убирали признак видимости у атрибутов и представлений, потому что, эти данные нужны только в вычислениях, и их не требуется отображать в интерфейсе.
Настройка типов данных
Настройка типов данных у атрибутов классов ‒ важный шаг, который определяет сопоставление типов данных для классов на диаграмме с классами в коде приложения или таблицами в базе данных, а также генерацию правил валидации в приложении. Рассмотрим в качестве примера класс “Invoice” (Накладная):
В данном классе у атрибута “ShipmentDateTime” (“Дата и время отгрузки”) указан тип “DateTime”. В связи с этим, если при сохранении модели на бэкенде это поле будет пустым, то оно по умолчанию будет заполнено значением “01.01.1901”. Это связано с тем, что в C# значение типа “DateTime” не может принимать нулевые (null) значения: в момент сохранения записи происходит автоприсвоение минимального валидного значения (01.01.1901). Нас такое поведение не устраивает, так как это поле в принципе может быть пустым (не по каждой накладной может быть осуществлена отгрузка в заданный момент времени).
Для решения описанной выше проблемы необходимо сопоставить тип данных на диаграмме класов с типом данных “DateTime?” при генерации приложения на языке C#.
Проверим, есть ли такой вариант среди типов, доступных “из коробки” во Flexberry Designer. Для этого откроем карту типов:
Стадия (ember) → Ember → [ПКМ] → Свойства модели → Карта типов
Мы можем увидеть, что в карте типов имеется три Nullable-типа: для даты, а также для целого и вещественного типа. Их можно использовать для решения подобной задачи, но, во-первых, не всегда необходимые Nullable-типы будут существовать в карте типов, а, во-вторых, всё-таки рекомендуется использовать стандартные типы языка C#, которые допускают значение null. Поэтому на примере данной ситуации разберем, как добавить свой собственный тип.
Добавим для новых типов данных отдельную диаграмму классов (Типы данных):
На созданной диаграмме создадим новый класс с именем “tDateTime” и стереотипом “typedef” (данный класс можно сразу свернуть, т.к. у него не будет никаких атрибутов и методов):
Теперь нужно определить, с какими типами данных наш новый тип будет сопоставляться при генерации приложения. Для этого снова перейдем к карте типов:
Стадия (ember) → [ПКМ] → Ember → Свойства модели → Карта типов
После создания класса со стереотипом “typedef”, в карте типов появился соответствующий тип данных. Назначим ему значение System.DateTime? в поле “отображается в”. Поле “файл со сборкой” оставим пустым (для системных типов это поле заполнять не требуется).
Аналогичные действия нужно выполнить и в карте типов для базы данных (требуется указать сопоставление нового типа данных с типом TIMESTAMP(3)):
Стадия (ember) → [ПКМ] → Ember → Storage → PostgreSQL → Настройка БД → Карта типов
Далее заменим соответствующие типы данных у атрибутов на диаграмме классов:
Итог
В результате всех проделанных ранее действий мы доработали диаграмму классов для генерации приложений и базы данных: настроены заголовки, порядок полей на формах, видимость полей на формах и т.п. Итоговый вариант диаграммы классов перед генерацией приложений и базы данных выглядит следующим образом: