diff --git a/pages/guides/practical-guides/flexberry-asp-net/gpg_auto-get-data-from-lookup.en.md b/pages/guides/practical-guides/flexberry-asp-net/gpg_auto-get-data-from-lookup.en.md index a00f2d4e8..293679fd8 100644 --- a/pages/guides/practical-guides/flexberry-asp-net/gpg_auto-get-data-from-lookup.en.md +++ b/pages/guides/practical-guides/flexberry-asp-net/gpg_auto-get-data-from-lookup.en.md @@ -31,21 +31,23 @@ using ICSSoft.STORMNET.Windows.Forms; ```csharp protected override void PreApplyToControls() { - if (IsPostBack && (DataObject == null || DataObject.GetStatus(true) == ObjectStatus.Created)) - { - var заказ = ctrlЗаказ.SelectedMasterPK; - ctrlЗаказ.MasterViewName = Заказ.Views.ЗаказL.Name; - - var lcs = LoadingCustomizationStruct.GetSimpleStruct(typeof(СтрокаЗаказа), СтрокаЗаказа.Views.СтрокаЗаказаE); - lcs.LimitFunction = FunctionBuilder.BuildEquals<СтрокаЗаказа>(x => x.Заказ, заказ); - var строкиЗаказа = DataServiceProvider.DataService.LoadObjects(lcs); - - foreach (var s in строкиЗаказа) - { - var строкаЗаказа = (СтрокаЗаказа)s; - DataObject.ЗаписьВНакладной.Add(new ЗаписьВНакладной { Количество = строкаЗаказа.Количество, Товар = строкаЗаказа.Товар }); - } - } +if (IsPostBack && (DataObject == null || DataObject.GetStatus(true) == ObjectStatus.Created)) +{ +var заказ = ctrlЗаказ.SelectedMasterPK; + ctrlЗаказ.MasterViewName = Заказ.Views.ЗаказL.Name; + + var lcs = LoadingCustomizationStruct.GetSimpleStruct(typeof(СтрокаЗаказа), СтрокаЗаказа.Views.СтрокаЗаказаE); + lcs.LimitFunction = FunctionBuilder.BuildEquals<СтрокаЗаказа>(x => x.Заказ, заказ); + IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. + IDataService ds = mainUnityContainer.Resolve(); + var строкиЗаказа = ds.LoadObjects(lcs); + + foreach (var s in строкиЗаказа) + { + var строкаЗаказа = (СтрокаЗаказа)s; + DataObject.ЗаписьВНакладной.Add(new ЗаписьВНакладной { Количество = строкаЗаказа.Количество, Товар = строкаЗаказа.Товар }); + } + } } ``` diff --git a/pages/guides/practical-guides/flexberry-asp-net/gpg_auto-get-data-from-lookup.ru.md b/pages/guides/practical-guides/flexberry-asp-net/gpg_auto-get-data-from-lookup.ru.md index f91ed1e63..48c2cac6f 100644 --- a/pages/guides/practical-guides/flexberry-asp-net/gpg_auto-get-data-from-lookup.ru.md +++ b/pages/guides/practical-guides/flexberry-asp-net/gpg_auto-get-data-from-lookup.ru.md @@ -29,21 +29,23 @@ using ICSSoft.STORMNET.Windows.Forms; ```csharp protected override void PreApplyToControls() { - if (IsPostBack && (DataObject == null || DataObject.GetStatus(true) == ObjectStatus.Created)) - { - var заказ = ctrlЗаказ.SelectedMasterPK; - ctrlЗаказ.MasterViewName = Заказ.Views.ЗаказL.Name; - - var lcs = LoadingCustomizationStruct.GetSimpleStruct(typeof(СтрокаЗаказа), СтрокаЗаказа.Views.СтрокаЗаказаE); - lcs.LimitFunction = FunctionBuilder.BuildEquals<СтрокаЗаказа>(x => x.Заказ, заказ); - var строкиЗаказа = DataServiceProvider.DataService.LoadObjects(lcs); - - foreach (var s in строкиЗаказа) - { - var строкаЗаказа = (СтрокаЗаказа)s; - DataObject.ЗаписьВНакладной.Add(new ЗаписьВНакладной { Количество = строкаЗаказа.Количество, Товар = строкаЗаказа.Товар }); - } - } + if (IsPostBack && (DataObject == null || DataObject.GetStatus(true) == ObjectStatus.Created)) + { + var заказ = ctrlЗаказ.SelectedMasterPK; + ctrlЗаказ.MasterViewName = Заказ.Views.ЗаказL.Name; + + var lcs = LoadingCustomizationStruct.GetSimpleStruct(typeof(СтрокаЗаказа), СтрокаЗаказа.Views.СтрокаЗаказаE); + lcs.LimitFunction = FunctionBuilder.BuildEquals<СтрокаЗаказа>(x => x.Заказ, заказ); + IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. + IDataService ds = mainUnityContainer.Resolve(); + var строкиЗаказа = ds.LoadObjects(lcs); + + foreach (var s in строкиЗаказа) + { + var строкаЗаказа = (СтрокаЗаказа)s; + DataObject.ЗаписьВНакладной.Add(new ЗаписьВНакладной { Количество = строкаЗаказа.Количество, Товар = строкаЗаказа.Товар }); + } + } } ``` diff --git a/pages/guides/practical-guides/flexberry-asp-net/gpg_business-server.ru.md b/pages/guides/practical-guides/flexberry-asp-net/gpg_business-server.ru.md index d66e00f9d..398f0ecbc 100644 --- a/pages/guides/practical-guides/flexberry-asp-net/gpg_business-server.ru.md +++ b/pages/guides/practical-guides/flexberry-asp-net/gpg_business-server.ru.md @@ -16,15 +16,15 @@ lang: ru 1.Добавить на диаграмму классов класс со стереотипом `businessserver`. -![](/images/pages/guides/flexberry-aspnet/add-bsclass.png) +![add-bsclas](/images/pages/guides/flexberry-aspnet/add-bsclass.png) 2.Сохранить диаграмму, в свойствах класса `Заказ` указать соответствующее имя бизнес-сервера и сохранить форму редактирования класса. Затем, из появившегося выпадающего списка, выбрать срабатывание на `OnAllEvents` (т.е. при любых операциях сервиса данных): -![](/images/pages/guides/flexberry-aspnet/set-bsclass-in-zakaz.png) +![set-bsclass-in-zakaz](/images/pages/guides/flexberry-aspnet/set-bsclass-in-zakaz.png) 3.Сохранить диаграмму. Сгенерировать бизнес-серверы и объекты данных. -![](/images/pages/guides/flexberry-aspnet/gen-bs-and-objects.png) +![gen-bs-and-objects](/images/pages/guides/flexberry-aspnet/gen-bs-and-objects.png) 4.Проект с бизнес-серверами добавить в `Solution`. Добавить ссылку на проект с бизнес-сервером в проекты приложений. 5.После этого прописать в скобках программиста следующие строчки (для выбора вариантов используется сочетание `Ctrl`+Пробел): @@ -38,127 +38,127 @@ using ICSSoft.STORMNET.FunctionalLanguage; using ICSSoft.STORMNET.FunctionalLanguage.SQLWhere; // *** End programmer edit section *** (Using statements) -``` +``` 6.Далее в коде бизнес-сервера обработать всё следующим образом: ```csharp public virtual ICSSoft.STORMNET.DataObject[] OnUpdateЗаказ(АСУ_Склад.Заказ UpdatedObject) { - // *** Start programmer edit section *** (OnUpdateЗаказ) - - // Определим массив, который будем возвращать для обновления. - DataObject[] ret = new DataObject[0]; - - // Проверим на то, что пришедший объект - это именно то, что нам нужно (создан или изменён и статус установлен в Оплачено). - if ((UpdatedObject.GetStatus() == ICSSoft.STORMNET.ObjectStatus.Created || UpdatedObject.GetStatus() == ICSSoft.STORMNET.ObjectStatus.Altered) && Array.IndexOf(UpdatedObject.GetAlteredPropertyNames(), "Статус") >= 0 && UpdatedObject.Статус == СостояниеЗаказа.Оплаченный) - { - // Построим ограничение и вычитаем все объекты ТоварНаСкладе, которые нам подходят. - Заказ заказ = UpdatedObject; - ICSSoft.STORMNET.FunctionalLanguage.Function lf = null; - - for (int i = 0; i < заказ.СтрокаЗаказа.Count; i++) - { - if (lf != null) - { - if (заказ.СтрокаЗаказа[i].Товар != null) - lf = FunctionBuilder.BuildOr( - lf, - FunctionBuilder.BuildEquals<ТоварНаСкладе>(x => x.Goods, заказ.СтрокаЗаказа[i].Товар)); - } - - else - { - if (заказ.СтрокаЗаказа[i].Товар != null) - lf = FunctionBuilder.BuildEquals<ТоварНаСкладе>(x => x.Goods, заказ.СтрокаЗаказа[i].Товар); - } - } - - ICSSoft.STORMNET.Business.LoadingCustomizationStruct lcs = ICSSoft.STORMNET.Business.LoadingCustomizationStruct.GetSimpleStruct(typeof(ТоварНаСкладе),"ТоварНаСкладеE"); - lcs.LimitFunction = lf; - ICSSoft.STORMNET.DataObject[] objs = ICSSoft.STORMNET.Business.DataServiceProvider.DataService.LoadObjects(lcs); - - // Разместим вычитанные объекты в отсортированном списке для удобного доступа в дальнейшем. - System.Collections.SortedList sl = new System.Collections.SortedList(); - - for (int i = 0; i < objs.Length; i++) - { - if (sl.ContainsKey(((ТоварНаСкладе)objs[i]).Товар.__PrimaryKey)) - { - ((System.Collections.ArrayList)sl[objs[i].__PrimaryKey]).Add(objs[i]); - } - else - { - System.Collections.ArrayList списокТоваров = new System.Collections.ArrayList(); - списокТоваров.Add(objs[i]); - sl.Add(((ТоварНаСкладе)objs[i]).Товар.__PrimaryKey, списокТоваров); - } - } - - // Определим строчку для сообщения об ошибке. - string errStr = string.Empty; - ArrayList retObjs = new ArrayList(); - - // Проверим наличие товара на складах, если не хватает, то выдадим сообщение об ошибке, если хватает, то вычитаем количество. - for (int i = 0; i < заказ.СтрокаЗаказа.Count; i++) - { - if (sl.ContainsKey(заказ.СтрокаЗаказа[i].Товар.__PrimaryKey)) - { - ArrayList arl = ((System.Collections.ArrayList)sl[заказ.СтрокаЗаказа[i].Товар.__PrimaryKey]); - - int количествоНаСкладах = 0; for (int j = 0; j < arl.Count; j++) - { - количествоНаСкладах += - ((ТоварНаСкладе)arl[j]).Количество; - } - - if (количествоНаСкладах < - заказ.СтрокаЗаказа[i].Количество) - { - errStr += " Не хватает товара \"" + заказ.СтрокаЗаказа[i].Товар.Название + "\" в наличии: " + количествоНаСкладах + ", требуется " + заказ.СтрокаЗаказа[i].Количество + Environment.NewLine; - } - else - { - int колич = заказ.СтрокаЗаказа[i].Количество; - for (int j = 0; j < arl.Count; j++) - { - if (колич > 0 && - ((ТоварНаСкладе)arl[j]).Количество > колич) - { - ((ТоварНаСкладе)arl[j]).Количество -= колич; - колич = 0; retObjs.Add(arl[j]); - } - else - { - if (колич > 0) - { - колич -= ((ТоварНаСкладе)arl[j]).Количество; - ((ТоварНаСкладе)arl[j]).Количество = 0; - retObjs.Add(arl[j]); - } - } - } - } - } - else - { - errStr += "Товар \"" + - заказ.СтрокаЗаказа[i].Товар.Название + "\" в наличии отсутствует." + Environment.NewLine; - } - } - - // В случае, если чего-то не хватило, сообщаем об этом пользователю. - if (errStr != string.Empty) - { - throw new Exception(errStr); - } - - // Если всё нормально, то возвращаем массив объектов, которые надо обновить. - ret = new DataObject[retObjs.Count]; retObjs.CopyTo(ret, 0); - } - return ret; - - // *** End programmer edit section *** (OnUpdateЗаказ) + // *** Start programmer edit section *** (OnUpdateЗаказ) + + // Определим массив, который будем возвращать для обновления. + DataObject[] ret = new DataObject[0]; + + // Проверим на то, что пришедший объект - это именно то, что нам нужно (создан или изменён и статус установлен в Оплачено). + if ((UpdatedObject.GetStatus() == ICSSoft.STORMNET.ObjectStatus.Created || UpdatedObject.GetStatus() == ICSSoft.STORMNET.ObjectStatus.Altered) && Array.IndexOf(UpdatedObject.GetAlteredPropertyNames(), "Статус") >= 0 && UpdatedObject.Статус == СостояниеЗаказа.Оплаченный) + { + // Построим ограничение и вычитаем все объекты ТоварНаСкладе, которые нам подходят. + Заказ заказ = UpdatedObject; + ICSSoft.STORMNET.FunctionalLanguage.Function lf = null; + + for (int i = 0; i < заказ.СтрокаЗаказа.Count; i++) + { + if (lf != null) + { + if (заказ.СтрокаЗаказа[i].Товар != null) + lf = FunctionBuilder.BuildOr( + lf, + FunctionBuilder.BuildEquals<ТоварНаСкладе>(x => x.Goods, заказ.СтрокаЗаказа[i].Товар)); + } + + else + { + if (заказ.СтрокаЗаказа[i].Товар != null) + lf = FunctionBuilder.BuildEquals<ТоварНаСкладе>(x => x.Goods, заказ.СтрокаЗаказа[i].Товар); + } + } + + ICSSoft.STORMNET.Business.LoadingCustomizationStruct lcs = ICSSoft.STORMNET.Business.LoadingCustomizationStruct.GetSimpleStruct(typeof(ТоварНаСкладе),"ТоварНаСкладеE"); + lcs.LimitFunction = lf; + IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. + IDataService ds = mainUnityContainer.Resolve(); + ICSSoft.STORMNET.DataObject[] objs = ICSSoft.STORMNET.Business.ds.LoadObjects(lcs); + + // Разместим вычитанные объекты в отсортированном списке для удобного доступа в дальнейшем. + System.Collections.SortedList sl = new System.Collections.SortedList(); + + for (int i = 0; i < objs.Length; i++) + { + if (sl.ContainsKey(((ТоварНаСкладе)objs[i]).Товар.__PrimaryKey)) + { + ((System.Collections.ArrayList)sl[objs[i].__PrimaryKey]).Add(objs[i]); + } + else + { + System.Collections.ArrayList списокТоваров = new System.Collections.ArrayList(); + списокТоваров.Add(objs[i]); + sl.Add(((ТоварНаСкладе)objs[i]).Товар.__PrimaryKey, списокТоваров); + } + } + + // Определим строчку для сообщения об ошибке. + string errStr = string.Empty; + ArrayList retObjs = new ArrayList(); + + // Проверим наличие товара на складах, если не хватает, то выдадим сообщение об ошибке, если хватает, то вычитаем количество. + for (int i = 0; i < заказ.СтрокаЗаказа.Count; i++) + { + if (sl.ContainsKey(заказ.СтрокаЗаказа[i].Товар.__PrimaryKey)) + { + ArrayList arl = ((System.Collections.ArrayList)sl[заказ.СтрокаЗаказа[i].Товар.__PrimaryKey]); + + int количествоНаСкладах = 0; for (int j = 0; j < arl.Count; j++) + { + количествоНаСкладах += + ((ТоварНаСкладе)arl[j]).Количество; + } + + if (количествоНаСкладах < заказ.СтрокаЗаказа[i].Количество) + { + errStr += " Не хватает товара \"" + заказ.СтрокаЗаказа[i].Товар.Название + "\" в наличии: " + количествоНаСкладах + ", требуется " + заказ.СтрокаЗаказа[i].Количество + Environment.NewLine; + } + else + { + int колич = заказ.СтрокаЗаказа[i].Количество; + for (int j = 0; j < arl.Count; j++) + { + if (колич > 0 && ((ТоварНаСкладе)arl[j]).Количество > колич) + { + ((ТоварНаСкладе)arl[j]).Количество -= колич; + колич = 0; retObjs.Add(arl[j]); + } + else + { + if (колич > 0) + { + колич -= ((ТоварНаСкладе)arl[j]).Количество; + ((ТоварНаСкладе)arl[j]).Количество = 0; + retObjs.Add(arl[j]); + } + } + } + } + } + else + { + errStr += "Товар \"" + + заказ.СтрокаЗаказа[i].Товар.Название + "\" в наличии отсутствует." + Environment.NewLine; + } + } + + // В случае, если чего-то не хватило, сообщаем об этом пользователю. + if (errStr != string.Empty) + { + throw new Exception(errStr); + } + + // Если всё нормально, то возвращаем массив объектов, которые надо обновить. +ret = new DataObject[retObjs.Count]; retObjs.CopyTo(ret, 0); + } + return ret; + + // *** End programmer edit section *** (OnUpdateЗаказ) } ``` diff --git a/pages/guides/practical-guides/flexberry-ember/gpg_server-logic-implementation.md b/pages/guides/practical-guides/flexberry-ember/gpg_server-logic-implementation.md index ea49d7f7f..dcaca6ebe 100644 --- a/pages/guides/practical-guides/flexberry-ember/gpg_server-logic-implementation.md +++ b/pages/guides/practical-guides/flexberry-ember/gpg_server-logic-implementation.md @@ -7,32 +7,32 @@ permalink: ru/gpg_server-logic-implementation.html lang: ru --- -Рассмотрим пример типовой задачи, которую можно решить на стороне сервера. Пусть существует определенный заказ в статусе "Новый". Он содержит ряд строк с указанными товарами и их количеством на складе. Покупатель оплачивает заказ, следовательно, товары, входящие в его покупку, должны стать недоступны для повторной покупки. То есть оплаченный товар перестает быть "товаром в магазине" и становится собственностью покупателя. В такой ситуации при переводе заказа в статус "Оплаченный" товар должен списаться со складов. +Реализация серверной логики будет продемонстрирована на примере типовой задачи, которую можно решить на стороне сервера. Пусть существует определенный заказ в статусе "Новый". Он содержит ряд строк с указанными товарами и их количеством на складе. Покупатель оплачивает заказ, следовательно, товары, входящие в его покупку, должны стать недоступны для повторной покупки. То есть оплаченный товар перестает быть "товаром в магазине" и становится собственностью покупателя. В такой ситуации при переводе заказа в статус "Оплаченный" товар должен списаться со складов. -Решение данной задачи не требует динамического отклика на стороне клиента и, соответственно, может быть реализовано в процессе обработки запроса об изменении статуса заказа на стороне сервера. Следовательно, нам нужно отследить, когда **заказ** будет находиться **в состоянии Update** с изменением статуса на **Paid**. В этом случае нам нужно выполнить поиск товара на складах и списать товар. При этом если определенного товара на складе более не остается, нужно удалить запись об этом товаре: +Решение данной задачи не требует динамического отклика на стороне клиента и, соответственно, может быть реализовано в процессе обработки запроса об изменении статуса заказа на стороне сервера. Следовательно, нужно отследить, когда **заказ** будет находиться **в состоянии Update** с изменением статуса на **Paid**. В этом случае нужно выполнить поиск товара на складах и списать товар. При этом если определенного товара на складе более не остается, нужно удалить запись об этом товаре: ![Логика бизнес-сервера на смену статуса заказа](/images/pages/guides/flexberry-ember/7-2-server-logic-implementation/7-2-1.png) -Разобьем данную логику на конкретные шаги: +Для решения задачи можно выделить следующие шаги: 1. уточнить состояние (заказ может быть новым или измененным) и статус заказа (проверяем, чтобы заказ имел статус "Оплаченный"); 2. вычитать и отсортировать все записи о товарах на складах в соответствии со списком товаров в заказе; 3. перебрать все товары определенного типа на всех складах и: + - если товара на складах недостаточно - вывести сообщение об ошибке; - если конкретного товара на очередном складе достаточно, то списать нужное количество товара и обнулить счетчик списания; - если конкретного товара на очередном складе недостаточно, то удалить запись о текущем товаре на данном складе и уменьшить счетчик списания на то количество товара, которое имеется на данном складе. -**Реализуем** эту **логику** в ранее созданном бизнес-сервере **OrderBS**. В процессе работы используйте брейкпоинты, чтобы контролировать значения переменных. +Реализовать эту логику можно в ранее созданном бизнес-сервере **OrderBS**. В процессе работы рекомендуется использовать брейкпоинты, чтобы контролировать значения переменных. ## Условия применения логики -Прежде всего, необходимо реализовать проверку необходимых условий для применения описанной логики (шаг 1). Для этого в секции программиста (между комментариями "Start" и "End") **в теле** метода **OnUpdateOrder** проверим ряд условий: +Прежде всего, следует реализовать проверку ключевых условий для применения описанной логики (шаг 1). Для этого в секции программиста (между комментариями "Start" и "End") **в теле** метода **OnUpdateOrder** проверяется ряд условий: -{% highlight csharp%} -{% raw %} +'''csharp public virtual ICSSoft.STORMNET.DataObject[] OnUpdateOrder(IIS.Shop.Order UpdatedObject) { - // *** Start programmer edit section *** (OnUpdateOrder) + // \*** Start programmer edit section *** (OnUpdateOrder) if ((UpdatedObject.GetStatus() == ObjectStatus.Created || UpdatedObject.GetStatus() == ObjectStatus.Altered) && Array.IndexOf(UpdatedObject.GetAlteredPropertyNames(), "Status") >= 0 @@ -44,25 +44,23 @@ public virtual ICSSoft.STORMNET.DataObject[] OnUpdateOrder(IIS.Shop.Order Update return new ICSSoft.STORMNET.DataObject[0]; // *** End programmer edit section *** (OnUpdateOrder) } -{% endraw %} -{% endhighlight %} +''' -В этом коде мы проверяем через операцию "или" два возможных состояния заказа (1 и 2 строки), а после с использованием операции "и" проверяем, что нам нужна запись, у которой поле "Статус" изменилось (3 строка) и равно на данный момент статусу "Оплачено" (4 строка). +В этом коде через операцию "или" проверяются два возможных состояния заказа (1 и 2 строки), а после с использованием операции "и" - что нужна запись, у которой поле "Статус" изменилось (3 строка) и равно на данный момент статусу "Оплачено" (4 строка). -{% include important.html content="Мы сравниваем статус не просто со строкой "Paid", мы берем соответствующее значение из перечисления OrderStatus." %} +> Сравнение статуса происходит не просто со строкой *Paid*,берется соответствующее значение из перечисления OrderStatus. -При добавлении данного кода обращение к объекту **ObjectStatus** будет подчеркнуто **красным цветом**. Для того, чтобы исправить эту ошибку, нам нужно указать использование соответствующего пространства имен в данном классе. Для исправления подобных ошибок можно **навести курсор** на "проблемный" объект, раскрыть **список предлагаемых исправлений** и выбрать **подключение** требуемого **пространства имен**: +При добавлении данного кода обращение к объекту **ObjectStatus** будет подчеркнуто **красным цветом**. Для того чтобы исправить эту ошибку, необходимо указать использование соответствующего пространства имен в данном классе. Для исправления подобных ошибок можно **навести курсор** на "проблемный" объект, раскрыть **список предлагаемых исправлений** и выбрать **подключение** требуемого **пространства имен**: ![Подключение пространства имен ICSSoft.STORMNET](/images/pages/guides/flexberry-ember/7-2-server-logic-implementation/7-2-3.png) -{% include important.html content="Каждый раз, когда вы добавляете новый using в коде, необходимо перезапускать приложение. Это нельзя сделать в режиме паузы (Break Mode)." %} +> Каждый раз, когда добавлен новый using в коде, необходимо перезапускать приложение. Это нельзя сделать в режиме паузы (Break Mode). Если все выполнено верно, то ошибка исчезнет. -Дальнейший код, который мы добавим, может выглядеть достаточно громоздко. Поэтому **создадим** для действий с Заказом и Товарами на складах отдельный **метод changeOrderStatusPaid()**, который будет возвращать список измененных объектов в основной метод бизнес-сервера: +Дальнейший код, может выглядеть достаточно громоздко. Поэтому для действий с Заказом и Товарами на складах создается отдельный **метод changeOrderStatusPaid()**, который будет возвращать список измененных объектов в основной метод бизнес-сервера: -{% highlight csharp%} -{% raw %} +'''csharp public class OrderBS : ICSSoft.STORMNET.Business.BusinessServer { @@ -102,27 +100,27 @@ public class OrderBS : ICSSoft.STORMNET.Business.BusinessServer // *** End programmer edit section *** (OnUpdateOrder) } } -{% endraw %} -{% endhighlight %} +''' + +> include note.html content="Для добавленного метода changeOrderStatusPaid следует учитывать два момента: -{% include note.html content="Для добавленного метода changeOrderStatusPaid следует учитывать два момента: -1. Данный метод у нас помечен модификатором доступа private: он будет недоступен из других классов. Такое объявление является предпочтительным, так как метод реализует внутреннюю логику и нигде больше не будет использоваться. -2. Данный метод мы добавили перед основным методом бизнес-сервера, в специально отведенном скобками разработчика месте. Это нужно для того, чтобы наш метод при перегенерации сохранился." %} + 1. Данный метод у помечен модификатором доступа private: он будет недоступен из других классов. Такое объявление является предпочтительным, так как метод реализует внутреннюю логику и нигде больше не будет использоваться. + 2. Данный метод добавлен перед основным методом бизнес-сервера, в специально отведенном скобками разработчика месте. Это нужно для того, чтобы метод при перегенерации сохранился. Прежде всего, для любого метода рекомендуется добавлять **комментарии для автодокументации** ([Documentation comments](https://docs.microsoft.com/ru-ru/dotnet/csharp/language-reference/language-specification/documentation-comments)), в которой минимально указываются: -1. {% raw %}{% endraw %} - описание метода; -2. {% raw %}{% endraw %} - параметр метода с указанием имени и описания; -3. {% raw %}{% endraw %} - описание возвращаемых значений (если метод возвращает не void). -Кроме того, так как мы будем в дальнейшем часто использовать тип **DataObject**, мы **упростили обращение** к нему, добавив требуемое пространство имен с использованием **конструкции using**, и тем самым избавились от необходимости писать полное имя типа - ICSSoft.STORMNET.DataObject. +1. - описание метода; +2. - параметр метода с указанием имени и описания; +3. - описание возвращаемых значений (если метод возвращает не void). -**Вызовем добавленный метод** (changeOrderStatusPaid) из основного (OnUpdateOrder) и вернуть его результат в качестве списка измененных объектов: +Кроме того, так как в дальнейшем будет часто использоваться тип **DataObject**, упрощено обращение к нему через добавление требуемого пространства имен с использованием **конструкции using**, таким образом, нет необходимости писать полное имя типа - ICSSoft.STORMNET.DataObject. -{% highlight csharp%} -{% raw %} +Вызов добавленного метода (changeOrderStatusPaid) из основного (OnUpdateOrder) и возвращение его результата в качестве списка измененных объектов: + +'''csharp public virtual DataObject[] OnUpdateOrder(IIS.Shop.Order UpdatedObject) { - // *** Start programmer edit section *** (OnUpdateOrder) + // \*** Start programmer edit section *** (OnUpdateOrder) DataObject[] result = new DataObject[0]; if ((UpdatedObject.GetStatus() == ObjectStatus.Created @@ -136,39 +134,37 @@ public virtual DataObject[] OnUpdateOrder(IIS.Shop.Order UpdatedObject) return result; // *** End programmer edit section *** (OnUpdateOrder) } -{% endraw %} -{% endhighlight %} +''' -{% include note.html content="При наличии нескольких методов, которые могут изменять объекты данных, необходимо все измененные объекты добавлять к одному общему списку, а не заменять целиком данный список." %} +> При наличии нескольких методов, которые могут изменять объекты данных, необходимо все измененные объекты добавлять к одному общему списку, а не заменять целиком данный список. -**Проверим**, все ли верно мы выполнили. Для этого запустим сервер в **режиме отладки** и поставим **брейкпоинт** в строку с оператором **return** в методе **changeOrderStatusPaid**: +Для проверки правильности выполнения следует запустить сервер в режиме отладки с установленным брейкпоинтом в строке с оператором **return** в методе **changeOrderStatusPaid**: ![Брейкопинт в методе changeOrderStatusPaid](/images/pages/guides/flexberry-ember/7-2-server-logic-implementation/7-2-6.png) -В клиентском приложении **переведем** Заказ 2 в статус "Оплаченный" и сохраним его: на сервере сработает созданный брейкпоинт в новом методе. Продолжим выполнение кода на сервере (кнопка Continue) и обновим страницу в браузере: убедимся, что все изменения сохранились. Далее переведем текущий заказ обратно в статус "Новый" и сохраним его: брейкпоинт в данном случае не сработает. Это означает, что метод работает корректно - метод changeOrderStatusPaid не будет вызываться для новых заказов. +В клиентском приложении Заказ 2 необходимо перевести в статус "Оплаченный" и сохранить его: на сервере сработает созданный брейкпоинт в новом методе. Продолжить выполнения кода на сервере (кнопка Continue) и обновить страницу в браузере: все изменения должны быть сохранены. Далее текущий заказ следует перевести обратно в статус "Новый" и сохранить его: брейкпоинт в данном случае не сработает. Это означает, что метод работает корректно - метод changeOrderStatusPaid не будет вызываться для новых заказов. ## Реализация основной части логики -Теперь, когда для логики перевода Заказа в статус "Оплаченный" создан отдельный метод, можно реализовывать основной функционал. Аналогичная логика реализована в разделе "[Работа с бизнес-сервером](gpg_business-server.html)" (Практическое руководство по веб-разработке на Flexberry ASP.NET). +После реализации логики перевода Заказа в статус "Оплаченный" создан отдельный метод. Следовательно, можно реализовывать основной функционал. Аналогичная логика реализована в разделе "[Работа с бизнес-сервером](gpg_business-server.html)" (Практическое руководство по веб-разработке на Flexberry ASP.NET). -{% include important.html content="Всю дальнейшую логику мы будем проверять на примере Заказа 2." %} +> Всю дальнейшую логику мы будем проверять на примере Заказа 2. -В числе вносимых в код **изменений** (по сравнению с кодом, который представлен по ссылке выше) мы добавим возможность сортировки вычитываемых товарных позиций со складов по номеру склада. Для этого нужно обновить класс StoreProduct во **Flexberry Designer**: необходимо добавить невидимый атрибут **Storehouse.Number** в представление **StoreProductE**. +В числе вносимых в код изменений (по сравнению с кодом, который представлен по ссылке выше) будет добавлена возможность сортировки вычитываемых товарных позиций со складов по номеру склада. Для этого нужно обновить класс StoreProduct во Flexberry Designer: добавить невидимый атрибут **Storehouse.Number** в представление **StoreProductE**. ![Добавление свойства Storehouse.Number в представление StoreProductE](/images/pages/guides/flexberry-ember/7-2-server-logic-implementation/7-2-7.png) -После этого следует **обновить проект с объектами данных на бэкенде** (выполнить перегенерацию соответствующего проекта). Теперь мы легко получим доступ из объекта конкретной позиции товара на складе к характеристике самого склада, в частности к его номеру. Условимся, что товары будут списываться всегда со складов в порядке увеличения порядкового номера склада. +После этого следует обновить проект с объектами данных на бэкенде (выполнить перегенерацию соответствующего проекта). Теперь существует доступ из объекта конкретной позиции товара на складе к характеристике самого склада, в частности к его номеру. Предположительно, товары будут списываться всегда со складов в порядке увеличения порядкового номера склада. -Реализуем теперь основную логику. Прежде всего, нужно **вычитать список всех требуемых товарных позиций со всех складов**: +Реализация основной логики: прежде всего, нужно **вычитать список всех требуемых товарных позиций со всех складов**: -{% highlight csharp%} -{% raw %} +'''charp private static DataObject[] changeOrderStatusPaid(IIS.Shop.Order UpdatedObject) { - // Определим массив, который будем возвращать для обновления. + // Массив, который будет возвращен для обновления. DataObject[] ret = new DataObject[0]; - // Построим ограничение и вычитаем все объекты StoreProduct, которые нам подходят. + // Ограничение и вычитка всех объектов StoreProduct, которые подходят. Order order = UpdatedObject; Function lf = null; @@ -188,31 +184,32 @@ private static DataObject[] changeOrderStatusPaid(IIS.Shop.Order UpdatedObject) var sortColumns = new List(); sortColumns.Add(new ColumnsSortDef("Storehouse.Number", SortOrder.Asc)); lcs.ColumnsSort = sortColumns.ToArray(); - - DataObject[] objs = DataServiceProvider.DataService.LoadObjects(lcs); + + IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. + IDataService ds = mainUnityContainer.Resolve(); + DataObject[] objs = ds.LoadObjects(lcs); return ret; // БРЕЙКПОИНТ } -{% endraw %} -{% endhighlight %} +''' -{% include note.html content="При вычитке данных здесь используется функционал класса FunctionBuilder. Существует другой метод вычитки из БД - Linq-запросы. Выбор конкретного зависит от проекта." %} +> При вычитке данных здесь используется функционал класса FunctionBuilder. Существует другой метод вычитки из БД - Linq-запросы. Выбор конкретного зависит от проекта. -**Результатом** выполнения данного участка кода является вычитанный из БД **список товарных позиций на складах в переменной objs**, соответствующих списку товаров в заказе. Проверим список объектов данных в этой переменной, установив **брейкпоинт** на **return ret** (см. предыдущий скриншот): мы ожидаем увидеть две записи (1 и 2 ед. товара на 1-м и 2-м складах соответственно). +Результатом выполнения данного участка кода является вычитанный из БД **список товарных позиций на складах в переменной objs**, соответствующих списку товаров в заказе. Необходимо проверить список объектов данных в этой переменной, установив **брейкпоинт** на **return ret** (см. предыдущий скриншот): отображены две записи (1 и 2 ед. товара на 1-м и 2-м складах соответственно). ![Содержимое переменной objs](/images/pages/guides/flexberry-ember/7-2-server-logic-implementation/7-2-9.png) -Далее для удобства работы сформируем **отсортированные** по первичному ключу товаров пары "ключ-значение", в которые в качестве значений добавим коллекцию вычитанных **товарных позиций** с соответствующим первичным ключом товара: +Далее для удобства работы следует сформировать **отсортированные** по первичному ключу товаров пары "ключ-значение", в которые в качестве значений будет добавлена коллекция вычитанных **товарных позиций** с соответствующим первичным ключом товара: -{% highlight csharp%} -{% raw %} +''' private static DataObject[] changeOrderStatusPaid(IIS.Shop.Order UpdatedObject) { ... + IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. + IDataService ds = mainUnityContainer.Resolve(); + DataObject[] objs = ds.LoadObjects(lcs); - DataObject[] objs = DataServiceProvider.DataService.LoadObjects(lcs); - - // Разместим вычитанные объекты в отсортированном списке для удобного доступа в дальнейшем. + // Размещение вычитанных объектов в отсортированном списке для удобного доступа в дальнейшем. SortedList sl = new SortedList(); for (int i = 0; i < objs.Length; i++) { @@ -233,27 +230,25 @@ private static DataObject[] changeOrderStatusPaid(IIS.Shop.Order UpdatedObject) return ret; // БРЕЙКПОИНТ } -{% endraw %} -{% endhighlight %} +''' -**Проверим** результат (брейкпоинт прежний). +**Проверка** результата (брейкпоинт прежний). ![Сортированный список товара на разных складах](/images/pages/guides/flexberry-ember/7-2-server-logic-implementation/7-2-11.png) -Теперь мы имеем единую структуру данных, которая хранит информацию о том, что товар с конкретным id найден на двух складах. +Теперь создана структура данных, которая хранит информацию о том, что товар с конкретным id найден на двух складах. -{% include note.html content="Объект в текущем на момент останова программы состоянии доступен для просмотра в любом месте, где к нему есть обращение в коде." %} +> Объект в текущем на момент останова программы состоянии доступен для просмотра в любом месте, где к нему есть обращение в коде. -**Реализуем** непосредственно **логику списания** товаров из оплаченного заказа со складов: +Реализация непосредственно **логики списания** товаров из оплаченного заказа со складов: -{% highlight csharp%} -{% raw %} +''' private static DataObject[] changeOrderStatusPaid(IIS.Shop.Order UpdatedObject) { - // Определим массив, который будем возвращать для обновления. + // Массив, который будет возвращаться для обновления. DataObject[] ret = new DataObject[0]; - // Построим ограничение и вычитаем все объекты StoreProduct, которые нам подходят. + // Ограничение и вычитка всех объектов StoreProduct, которые подходят. Order order = UpdatedObject; Function lf = null; @@ -274,9 +269,11 @@ private static DataObject[] changeOrderStatusPaid(IIS.Shop.Order UpdatedObject) sortColumns.Add(new ColumnsSortDef("Storehouse.Number", SortOrder.Asc)); lcs.ColumnsSort = sortColumns.ToArray(); - DataObject[] objs = DataServiceProvider.DataService.LoadObjects(lcs); + IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. + IDataService ds = mainUnityContainer.Resolve(); + DataObject[] objs = ds.LoadObjects(lcs); - // Разместим вычитанные объекты в отсортированном списке для удобного доступа в дальнейшем. + // Размещение вычитанных объектов в отсортированном списке для удобного доступа в дальнейшем. SortedList sl = new SortedList(); for (int i = 0; i < objs.Length; i++) { @@ -295,11 +292,11 @@ private static DataObject[] changeOrderStatusPaid(IIS.Shop.Order UpdatedObject) } } - // Определим строчку для сообщения об ошибке. + // Определение строки сообщения об ошибке. string errStr = string.Empty; ArrayList retObjs = new ArrayList(); - // Проверим наличие товара на складах, если не хватает, то выдадим сообщение об ошибке, если хватает, то вычитаем количество. + // Проверка наличия товара на складах, если не хватает, то выводится сообщение об ошибке, если хватает - вычитывается количество. for (int i = 0; i < order.OrderItem.Count; i++) { if (sl.ContainsKey(order.OrderItem[i].Product.__PrimaryKey)) @@ -341,60 +338,53 @@ private static DataObject[] changeOrderStatusPaid(IIS.Shop.Order UpdatedObject) } else { - errStr += "Товар \"" + + errStr += "Товар \"" + order.OrderItem[i].Product.Name + "\" в наличии отсутствует." + Environment.NewLine; } - // В случае, если чего-то не хватило, сообщаем об этом пользователю. + // В случае, если чего-то не хватило, вывести сообщение. if (errStr != string.Empty) { throw new Exception(errStr); } - // Если всё нормально, то возвращаем массив объектов, которые надо обновить. + // При отсутствии проблем вернуть массив объектов, которые надо обновить. ret = new DataObject[retObjs.Count]; retObjs.CopyTo(ret, 0); } return ret; } -{% endraw %} -{% endhighlight %} +''' -{% include note.html content="Для того, чтобы удалить запись из БД с использованием возможностей Flexberry ORM, достаточно присвоить ей статус Deleted и добавить к списку изменяемых объектов." %} +> Для того чтобы удалить запись из БД с использованием возможностей Flexberry ORM, достаточно присвоить ей статус Deleted и добавить к списку изменяемых объектов. -**Проверим**, как работает написанный нами код. Для этого зафиксируем для себя состояние складов до изменения статуса заказа: +Для проверки написанного кода рекомендуется зафиксировать состояние складов до изменения статуса заказа: ![Состояние складов до смены статуса](/images/pages/guides/flexberry-ember/7-2-server-logic-implementation/7-2-13.png) -Ожидаем, что на первом складе совсем не останется товара "Монитор игровой MSI Optix MAG241CP", а на втором останется только 1 ед. указанного товара. Для проверки выполним два шага: +Предположительно, на первом складе совсем не останется товара "Монитор игровой MSI Optix MAG241CP", а на втором останется только 1 ед. указанного товара. Для проверки можно выполнить шага: -
    -
  1. - Выставим Дату оплаты Заказу 2 перед изменением статуса
    - {% include important.html content="Если вы не проставите Дату оплаты, то в дальнейшем без нарушения логики или дополнительных действий (например, манипуляцией этим полем в БД) у вас не получится её выставить." %} -
  2. +1.Выставить Дату оплаты Заказу 2 перед изменением статуса. -
  3. - Переведем Заказ 2 в статус "Оплаченный", сохраним его и посмотрим, какие товары остались на складах: +> Если не проставитm Дату оплаты, то в дальнейшем без нарушения логики или дополнительных действий (например, манипуляцией этим полем в БД) её не получится выставить. - Состояние складов после смены статуса -
  4. +2.Перевести Заказ 2 в статус "Оплаченный", сохранить его и проверить остатки товаров на складах: -
+![Состояние складов после смены статуса](/images/pages/guides/flexberry-ember/7-2-server-logic-implementation/7-2-14.png) Код работает корректно: со складов списалось 2 единицы товара "Монитор игровой MSI Optix MAG241CP" в указанной нами последовательности. ## Итог -В результате действий, описанных в данной главе, мы реализовали часть серверной логики, которая отрабатывает в момент сохранения. Действия, произведенные на сервере, отличаются высоким уровнем безопасности, так как полностью изолированы от потенциального пользователя. Их скорость также выше, чем у аналогичных манипуляций на стороне клиента. + +В результате действий, описанных в данной главе, реализована часть серверной логики, которая отрабатывает в момент сохранения. Действия, произведенные на сервере, отличаются высоким уровнем безопасности, так как полностью изолированы от потенциального пользователя. Их скорость также выше, чем у аналогичных манипуляций на стороне клиента. Иногда в бизнес-серверах ember-приложений, сгенерированных при помощи Flexberry Designer, дублируется клиентская логика изменения в моделях. Это касается переопределения операций создания, обновления и удаления записей. ## Самостоятельная работа -Вы можете выполнить следующие доработки в приложении самостоятельно для более полной реализации функционала приложения: -1. при изменении статуса Заказа на "Оплаченный" создавать на стороне сервера Накладную, к которой был бы уже прикреплен заказ, установлены статус "Новый" и выставлена текущая дата создания. -## Перейти +Выполнить следующие доработки в приложении для более полной реализации функционала приложения: при изменении статуса Заказа на "Оплаченный" создавать на стороне сервера Накладную, к которой был бы уже прикреплен заказ, установлены статус "Новый" и выставлена текущая дата создания. -* [Практическое руководство «Делай как я»](gpg_landing-page.html) +## Перейти -* [Бизнес-серверы и режим отладки](gpg_business-servers-and-debug-mode.html) -* [Реализация презентационной логики](gpg_implementation-of-presentation-logic.html) +- [Практическое руководство «Делай как я»](gpg_landing-page.html) +- [Бизнес-серверы и режим отладки](gpg_business-servers-and-debug-mode.html) +- [Реализация презентационной логики](gpg_implementation-of-presentation-logic.html) diff --git a/pages/products/flexberry-aspnet/controls/limit-editor/fa_limit-function-parameters.ru.md b/pages/products/flexberry-aspnet/controls/limit-editor/fa_limit-function-parameters.ru.md index bd5359e06..08d7954be 100644 --- a/pages/products/flexberry-aspnet/controls/limit-editor/fa_limit-function-parameters.ru.md +++ b/pages/products/flexberry-aspnet/controls/limit-editor/fa_limit-function-parameters.ru.md @@ -9,7 +9,7 @@ lang: ru Для подстановки параметров в функцию в классе `ICSSoft.STORMNET.Web.Tools.AdvLimitUtils` есть метод: -```csharp +```csharp /// /// Подставить конкретные значения вместо параметров функции. /// @@ -17,17 +17,19 @@ lang: ru /// Справочник значений параметров (название параметра - значение). /// Функция, в которой все параметры заменены на соответствующие значения. public static Function SubstituteParameters(Function function, IDictionary paramValues) -``` +``` ## Пример ```csharp -ExternalLangDef externalLangDef = ExternalLangDef.LanguageDef; +IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. +IDataService ds = mainUnityContainer.Resolve(); +ExternalLangDef languageDef = new ExternalLangDef(ds) // Ограничивающая функция. - ICSSoft.STORMNET.FunctionalLanguage.Function limitFunction = externalLangDef.GetFunction( - externalLangDef.funcEQ, - new ParameterDef("Дата", externalLangDef.DateTimeType, false, "")); + ICSSoft.STORMNET.FunctionalLanguage.Function limitFunction = languageDef.GetFunction( + languageDef.funcEQ, + new ParameterDef("Дата", languageDef.DateTimeType, false, "")); // Функция с подставленным значением параметра. limitFunction = AdvLimitUtils.SubstituteParameters( diff --git a/pages/products/flexberry-aspnet/controls/limit-editor/fa_web-limit-editor-null.ru.md b/pages/products/flexberry-aspnet/controls/limit-editor/fa_web-limit-editor-null.ru.md index 266a7b02b..d8b0b56c5 100644 --- a/pages/products/flexberry-aspnet/controls/limit-editor/fa_web-limit-editor-null.ru.md +++ b/pages/products/flexberry-aspnet/controls/limit-editor/fa_web-limit-editor-null.ru.md @@ -11,9 +11,9 @@ lang: ru В [расширенном редакторе ограничений](fa_advanced-limit-editor.html) есть поддержка выражений Пусто/Непусто (Пусто/Заполнено). -![](/images/pages/products/flexberry-aspnet/controls/limit-editor/web-limit-editor-null.png) +![Ограничение](/images/pages/products/flexberry-aspnet/controls/limit-editor/web-limit-editor-null.png) -`Пусто` соответствует функции [funcIsNull](fo_func-is-null.html) из [SQLWhereLanguageDef](fo_function-list.html). +`Пусто` соответствует функции [funcIsNull](fo_func-is-null.html) из [SQLWhereLanguageDef](fo_function-list.html). `Непусто` соответствует функции funcNotIsNull из [ExternalLangDef](fo_external-lang-def.html). @@ -28,10 +28,11 @@ lang: ru ## Несравнимые с null свойства и Пусто/Непусто -Если имеется класс `Кредит` со свойством `СуммаКредита` вещественного типа, то при переводе в [LINQProvider|LinqProvider) оно будет представляться следующим образом: +Если имеется класс `Кредит` со свойством `СуммаКредита` вещественного типа, то при переводе в [LinqProvider](https://flexberry.github.io/ru/fo_linq-provider.html) оно будет представляться следующим образом: ``` csharp -var ds = (SQLDataService)DataServiceProvider.DataService; +IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. +IDataService ds = mainUnityContainer.Resolve(); IQueryable<Кредит> limit = ds.Query<Кредит>(Кредит.Views.C__КредитE).Where(x => (x.СуммаКредита as object) == null); ``` diff --git a/pages/products/flexberry-aspnet/controls/lookup/fa_lookup-limit-web.en.md b/pages/products/flexberry-aspnet/controls/lookup/fa_lookup-limit-web.en.md index d0bc784fe..cfa0690c0 100644 --- a/pages/products/flexberry-aspnet/controls/lookup/fa_lookup-limit-web.en.md +++ b/pages/products/flexberry-aspnet/controls/lookup/fa_lookup-limit-web.en.md @@ -24,9 +24,10 @@ When you create a new object of type `Кредит` need to choose `Клиент To build a restriction using [LINQProvider](fo_linq-provider.html): ```csharp -var ds = (SQLDataService) DataServiceProvider.DataService; +IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. +IDataService ds = mainUnityContainer.Resolve(); IQueryable<Клиент> limit = ds.Query<Клиент>(Клиент.Views.КлиентL).Where(klient => klient.Прописка.Contains("Perm")); -``` +``` Then get a restraining function using the class `LinqToLcs`: diff --git a/pages/products/flexberry-aspnet/controls/lookup/fa_lookup-limit-web.ru.md b/pages/products/flexberry-aspnet/controls/lookup/fa_lookup-limit-web.ru.md index 163af82c6..f7a1707e4 100644 --- a/pages/products/flexberry-aspnet/controls/lookup/fa_lookup-limit-web.ru.md +++ b/pages/products/flexberry-aspnet/controls/lookup/fa_lookup-limit-web.ru.md @@ -1,71 +1,73 @@ ---- -title: Наложение ограничения на LookUp в Web -sidebar: flexberry-aspnet_sidebar -keywords: Flexberry ASP-NET, Ограничения -toc: true -permalink: ru/fa_lookup-limit-web.html -lang: ru ---- - -По умолчанию при открытии формы на [LookUp](fa_lookup-overview.html) отображается полный список объектов, из которых необходимо выбрать значение. Однако, зачастую возникает ситуация, когда отображать полный список нельзя. - -Следовательно, возникает вопрос: каким образом ограничить выводимые данные при поднятии на LookUp? - -## Пример 1 - -Пусть дана следующая диаграмма. - -![](/images/pages/products/flexberry-aspnet/controls/lookup/filter-ex-diagram.png) - -При создании нового объекта типа `Кредит` необходимо выбрать `Клиента`, которому выдается данный кредит. Например, что введено ограничение: выдавать кредиты только лицам, проживающим в городе Перми (т.е. если `Прописка` Клиента содержит в себе "Пермь"). - -Построить ограничение, используя [LINQProvider](fo_linq-provider.html): - -```csharp -var ds = (SQLDataService) DataServiceProvider.DataService; -IQueryable<Клиент> limit = ds.Query<Клиент>(Клиент.Views.КлиентL).Where(klient => klient.Прописка.Contains("Пермь")); -``` - -Затем получить ограничивающую функцию, используя класс `LinqToLcs`: - -```csharp -Function onlyPermKlients = LinqToLcs.GetLcs(limit.Expression, Клиент.Views.КлиентL).LimitFunction; -``` - -Ограничить LookUp, установив поле `LimitFunction`: - -```csharp -ctrlКлиент.LimitFunction = onlyPermKlients; -``` - -В результате, при открытии лукап-формы Клиентов с этой страницы будут отображаться только Клиенты, у которых встречается слово "Пермь" в поле "Прописка". - -## Пример 2 - -Более сложная задача: пускай прописка представляет собой отдельный класс, таким образом, необходимо наложить ограничение на мастер мастера: - -![](/images/pages/products/flexberry-aspnet/controls/lookup/kredit-diagramm.png) - -Дополнительно, необходимо отображать только работающих `КредитныхИнспекторов`. - -1.Построить ограничения, испльзуя LINQ-провайдер: - -```csharp -var ds = (SQLDataService) DataServiceProvider.DataService; -IQueryable<Клиент> limit1 = ds.Query<Клиент>(Клиент.Views.КлиентL).Where(klient => klient.Прописка.Город == "Пермь"); -IQueryable<КредитныйИнспектор> limit2 = ds.Query<КредитныйИнспектор>(КредитныйИнспектор.Views.КредитныйИнспекторL).Where(insp => insp.Работает); -``` - -2.Получить ограничивающие функции: - -```csharp -Function onlyPermKlients = LinqToLcs.GetLcs(limit1.Expression, Клиент.Views.КлиентL).LimitFunction; -Function onlyWorkingInspektors = LinqToLcs.GetLcs(limit2.Expression, КредитныйИнспектор.Views.КредитныйИнспекторL).LimitFunction; -``` - -3.Устанавливаем ограничения на LookUpы для Клиентов и Инспекторов: - -```csharp -ctrlКлиент.LimitFunction = onlyPermKlients; -ctrlКредитныйИнспектор.LimitFunction = onlyWorkingInspektors; -``` +--- +title: Наложение ограничения на LookUp в Web +sidebar: flexberry-aspnet_sidebar +keywords: Flexberry ASP-NET, Ограничения +toc: true +permalink: ru/fa_lookup-limit-web.html +lang: ru +--- + +По умолчанию при открытии формы на [LookUp](fa_lookup-overview.html) отображается полный список объектов, из которых необходимо выбрать значение. Однако, зачастую возникает ситуация, когда отображать полный список нельзя. + +Следовательно, возникает вопрос: каким образом ограничить выводимые данные при поднятии на LookUp? + +## Пример 1 + +Пусть дана следующая диаграмма. + +![filter-ex-diagram](/images/pages/products/flexberry-aspnet/controls/lookup/filter-ex-diagram.png) + +При создании нового объекта типа `Кредит` необходимо выбрать `Клиента`, которому выдается данный кредит. Например, что введено ограничение: выдавать кредиты только лицам, проживающим в городе Перми (т.е. если `Прописка` Клиента содержит в себе "Пермь"). + +Построить ограничение, используя [LINQProvider](fo_linq-provider.html): + +```csharp +IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. +IDataService ds = mainUnityContainer.Resolve(); +IQueryable<Клиент> limit = ds.Query<Клиент>(Клиент.Views.КлиентL).Where(klient => klient.Прописка.Contains("Пермь")); +``` + +Затем получить ограничивающую функцию, используя класс `LinqToLcs`: + +```csharp +Function onlyPermKlients = LinqToLcs.GetLcs(limit.Expression, Клиент.Views.КлиентL).LimitFunction; +``` + +Ограничить LookUp, установив поле `LimitFunction`: + +```csharp +ctrlКлиент.LimitFunction = onlyPermKlients; +``` + +В результате, при открытии лукап-формы Клиентов с этой страницы будут отображаться только Клиенты, у которых встречается слово "Пермь" в поле "Прописка". + +## Пример 2 + +Более сложная задача: пускай прописка представляет собой отдельный класс, таким образом, необходимо наложить ограничение на мастер мастера: + +![kredit-diagramm](/images/pages/products/flexberry-aspnet/controls/lookup/kredit-diagramm.png) + +Дополнительно, необходимо отображать только работающих `КредитныхИнспекторов`. + +1.Построить ограничения, испльзуя LINQ-провайдер: + +```csharp +IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. +IDataService ds = mainUnityContainer.Resolve(); +IQueryable<Клиент> limit1 = ds.Query<Клиент>(Клиент.Views.КлиентL).Where(klient => klient.Прописка.Город == "Пермь"); +IQueryable<КредитныйИнспектор> limit2 = ds.Query<КредитныйИнспектор>(КредитныйИнспектор.Views.КредитныйИнспекторL).Where(insp => insp.Работает); +``` + +2.Получить ограничивающие функции: + +```csharp +Function onlyPermKlients = LinqToLcs.GetLcs(limit1.Expression, Клиент.Views.КлиентL).LimitFunction; +Function onlyWorkingInspektors = LinqToLcs.GetLcs(limit2.Expression, КредитныйИнспектор.Views.КредитныйИнспекторL).LimitFunction; +``` + +3.Устанавливаем ограничения на LookUpы для Клиентов и Инспекторов: + +```csharp +ctrlКлиент.LimitFunction = onlyPermKlients; +ctrlКредитныйИнспектор.LimitFunction = onlyWorkingInspektors; +``` diff --git a/pages/products/flexberry-aspnet/controls/wolv/fa_wolv-add-button.en.md b/pages/products/flexberry-aspnet/controls/wolv/fa_wolv-add-button.en.md index 6a8acdc6e..8da4bf10a 100644 --- a/pages/products/flexberry-aspnet/controls/wolv/fa_wolv-add-button.en.md +++ b/pages/products/flexberry-aspnet/controls/wolv/fa_wolv-add-button.en.md @@ -83,7 +83,9 @@ private void CustomToolbarButtonClickHandler(object sender, ToolBarBtnEventArgs { var objects = eventArgs.PrimaryKeys.Select(x => new Город { __PrimaryKey = Guid.Parse(x) }) .Cast().ToArray(); - DataServiceProvider.DataService.LoadObjects(objects, Город.Views.ГородL, true); + IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. + IDataService ds = mainUnityContainer.Resolve(); + ds.LoadObjects(objects, Город.Views.ГородL, true); SelectedCitiesLabel.Visible = SelectedCitiesList.Visible = true; foreach (var obj in objects) diff --git a/pages/products/flexberry-aspnet/controls/wolv/fa_wolv-add-button.ru.md b/pages/products/flexberry-aspnet/controls/wolv/fa_wolv-add-button.ru.md index 97a09b68d..abb14b57a 100644 --- a/pages/products/flexberry-aspnet/controls/wolv/fa_wolv-add-button.ru.md +++ b/pages/products/flexberry-aspnet/controls/wolv/fa_wolv-add-button.ru.md @@ -1,288 +1,292 @@ ---- -title: Добавление кнопки в тулбар или в строки WebObjectListView -sidebar: flexberry-aspnet_sidebar -keywords: Flexberry ASP-NET -toc: true -permalink: ru/fa_wolv-add-button.html -lang: ru ---- - -## Добавление кнопок в тулбар WOLV - -Чтобы добавить кнопку в Toolbar WOLV необходимо воспользоваться методом `AddImageButton(...)` списка. -Однако, прежде чем добавлять кнопку в Toolbar, стоит определиться, какой обработчик будет у данной кнопки: - -* Серверный -* Клиентский -* Серверный и клиентский. - -### Серверный обработчик - -Если обработчик должен быть серверным, то необходимо воспользоваться следующей перегрузкой метода `AddImageButton`: - -```csharp -/// -/// Метод для добавления пользовательской кнопки в тулбар с возможностью установки -/// серверного обработчика. -/// -/// Серверный идентификатор кнопки. -/// CSS класс, который применится к кнопке. -/// Текст подсказки к кнопке. -/// Серверный обработчик нажатия кнопки. -public void AddImageButton(string id, string cssClass, string alternateText, ToolBarBtnEventHandler clickHandler) -``` - -Как можно заметить, в метод передаётся ID кнопки, CSS-класс, текст всплывающей подсказки, а также серверный обработчик нажатия следующего вида: - -```csharp -public delegate void ToolBarBtnEventHandler(LinkButton sender, ToolBarBtnEventArgs eventArgs); -``` - -#### ToolBarBtnEventArgs - -`ToolBarBtnEventArgs` - аргументы, передаваемые в серверный обработчик нажатия кнопки в Toolbar'e WOLV. - -Информация, которую можно получить из `ToolBarBtnEventArgs`: - -| Название | Описание | -| -------- | -------- | -| `List PrimaryKeys` | Список ключей объектов, выделенных в списке. __Важно: если установлена опция "Выделить всё на всех страницах", то вернётся пустой список__. | -| `bool IsAllSelected` | Установлена ли опция "Выделить всё на всех страницах". | -| `WebObjectListView WOLV` | Экземпляр списка, на Toolbar'e которого была нажата кнопка. | -| `Function LimitFunction` | Ограничивающая функция, наложенная на список. | - -#### Пример использования - -```csharp -protected override void Preload() -{ - ... - WebObjectListView1.AddImageButton( - "TestToolbarServerButton", // ID кнопки - "wolv-test-toolbar-server-button", // CSS-Класс - "Тестовая серверная кнопка тулбара", // Текст всплывающей подсказки - CustomToolbarButtonClickHandler); // Обработчик - ... -} -... - -private void CustomToolbarButtonClickHandler(object sender, ToolBarBtnEventArgs eventArgs) -{ - TestToolbarButtonLabel.Visible = true; - - // Проверка свойства Wolv аргументов события. - if (eventArgs.Wolv != WebObjectListView1) - { - throw new Exception("Экземпляр WOLV в обработчике нажатия кнопки тулбара задан неверно."); - } - - // Проверка свойства PrimaryKeys. - if (eventArgs.PrimaryKeys.Count > 0) - { - var objects = eventArgs.PrimaryKeys.Select(x => new Город { __PrimaryKey = Guid.Parse(x) }) - .Cast().ToArray(); - DataServiceProvider.DataService.LoadObjects(objects, Город.Views.ГородL, true); - - SelectedCitiesLabel.Visible = SelectedCitiesList.Visible = true; - foreach (var obj in objects) - { - SelectedCitiesList.Controls.Add(new HtmlGenericControl("li") { InnerText = ((Город)obj).Наименование }); - } - } - - // Проверка свойства IsAllSelected. - AllIsSelectedLabel.Visible = eventArgs.IsAllSelected; -} -``` - -### Клиентский обработчик - -Если обработчик должен быть клиентским, необходимо воспользоваться следующей перегрузкой метода `AddImageButton`: - -```csharp -/// -/// Метод для добавления пользовательской кнопки в тулбар с возможностью установки -/// клиентского обработчика. -/// -/// Серверный идентификатор кнопки. -/// CSS класс, который применится к кнопке. -/// Текст подсказки к кнопке. -/// Наименование JS функции в глобальном объекте - клиентского обработчика нажатия кнопки. -/// Дополнительные параметры для JS обработчика. -public void AddImageButton(string id, string cssClass, string alternateText, string clientClickHandler, string clientClickAddParams) -``` - -Кроме ID, CSS-класса и текста всплывающей подсказки в метод также передается имя JS-функции, а также параметры, которые стоит передать в эту функцию. - -{% include note.html content="Передаётся имя JS-функции, а не её код." %} - -#### Пример использования - -```csharp -protected override void Preload() -{ - ... - WebObjectListView1.AddImageButton( - "TestToolbarClientButton", // ID кнопки - "wolv-test-toolbar-client-button", // CSS-класс - "Тестовая клиентская кнопка тулбара", // Текст подсказки - "ToolbarBtnClickAlert", // Название JS-функции. - // В принципе, вариант alert(\"Нажата пользовательская кнопка тулбара с клиентским обработчиком\"); - // тоже прокатывает, но при более сложных обработчиках может работать некорректно. - // Рекомендуется передавать имя функции и описывать её отдельно! - string.Empty); // Параметры, передаваемые в функцию ToolbarBtnClickAlert. - ... -} -``` - -### Серверный и клиентский обработчик - -Чтобы добавить кнопку с одновременно и серверным, и клиентским обработчиком, необходимо воспользоваться следующей перегрузкой метода `AddImageButton(...)`: - -```csharp -/// -/// Добавление кнопки на тулбар. -/// -/// Кнопка для добавления. -public void AddImageButton(LinkButton lb) -``` - -При использовании этого метода важно понимать следующее: - -1. Использовать этот метод необходимо только тогда, когда другие методы не подходят. -2. Вся настройка кнопки (включая внешний вид и стили) ложится на прикладного разработчика. - -#### Пример использования - -```csharp -var twoHandlersButton = new LinkButton -{ - OnClientClick = "alert('Сработал серверный обработчик кнопки с 2 обработчиками.');", - ID = "TwoHandlersButton", - CssClass = "ics-wolv-toolbar-button wolv-test-toolbar-client-server-button", -}; -twoHandlersButton.Click += CustomToolbarButtonClickHandler1; -twoHandlersButton.ToolTip = "Кнопка с двумя обработчиками."; -WebObjectListView1.AddImageButton(twoHandlersButton); -``` - -## Добавление кнопок в строки WOLV - -Чтобы добавить кнопку в Toolbar WOLV необходимо воспользоваться методом `AddImageButtonToRow(...)` списка. - -Однако, прежде чем добавлять кнопку в Toolbar, стоит определиться, какой обработчик будет у данной кнопки: - -* Серверный -* Клиентский. - -### Серверный обработчик - -Если обработчик должен быть серверным, то необходимо воспользоваться следующей перегрузкой метода `AddImageButtonToRow`: - -```csharp -/// -/// Добавить кнопку в каждую строку -/// -/// ID кнопки (прибавится индекс строки) -/// Класс контрола -/// Подпись -/// Серверное событие, которое придёт при нажатии -/// PrimaryKey объекта в строке можно получить так: -/// primaryKey = (sender as ImageButton).Attributes["pk"]; -/// -public void AddImageButtonToRow(string id, string cssClass, string alternateText, ToolBarBtnEventHandler clickHandler) -``` - -Как и в случае с добавлением серверной кнопки на Toolbar, в метод передаётся ID кнопки, CSS-класс, текст всплывающей подсказки, а также серверный обработчик нажатия следующего вида: - -```csharp -public delegate void ToolBarBtnEventHandler(LinkButton sender, ToolBarBtnEventArgs eventArgs); -``` - -#### ToolBarBtnEventArgs - -Аналогично EventArgs'ам Toolbar'a. - -#### Пример использования - -```csharp -protected override void Preload() -{ - ... - WebObjectListView1.AddImageButtonToRow( - "TestRowServerButton", // ID кнопки - "ics-wolv-toolbar-button ics-wolv-toolbar-button-icon wolv-test-row-server-button", // CSS-класс - "Тестовая серверная кнопка в строке", // Текст всплывающей подсказки - CustomToolbarButtonClickHandler); // Серверный обработчик нажатия - ... -} - -... - -private void CustomToolbarButtonClickHandler(object sender, ToolBarBtnEventArgs eventArgs) -{ - TestToolbarButtonLabel.Visible = true; - - // Проверка свойства Wolv аргументов события. - if (eventArgs.Wolv != WebObjectListView1) - { - throw new Exception("Экземпляр WOLV в обработчике нажатия кнопки тулбара задан неверно."); - } - - // Проверка свойства PrimaryKeys. - if (eventArgs.PrimaryKeys.Count > 0) - { - var objects = eventArgs.PrimaryKeys.Select(x => new Город { __PrimaryKey = Guid.Parse(x) }) - .Cast().ToArray(); - DataServiceProvider.DataService.LoadObjects(objects, Город.Views.ГородL, true); - - SelectedCitiesLabel.Visible = SelectedCitiesList.Visible = true; - foreach (var obj in objects) - { - SelectedCitiesList.Controls.Add(new HtmlGenericControl("li") { InnerText = ((Город)obj).Наименование }); - } - } - - // Проверка свойства IsAllSelected. - AllIsSelectedLabel.Visible = eventArgs.IsAllSelected; -} -``` - -### Клиентский обработчик - -Если обработчик должен быть клиентским, необходимо воспользоваться следующей перегрузкой метода `AddImageButton`: - -```csharp -/// -/// Добавить кнопку в каждую строку -/// -/// ID кнопки (прибавится индекс строки) -/// Класс контрола -/// Подпись -/// Имя клиентской функции, которая будет вызвана при клике -/// Дополнительные параметры, которые передадутся в клиентскую функцию -public void AddImageButtonToRow(string id, string cssClass, string alternateText, string clientClickHandler, string clientClickAddParams) -``` - -Кроме ID, CSS-класса и текста всплывающей подсказки в метод также передается имя JS-функции, а также параметры, которые стоит передать в эту функцию. - -{% include note.html content="Передаётся имя JS-функции, а не её код." %} - -#### Пример использования - -```csharp -protected override void Preload() -{ - ... - WebObjectListView1.AddImageButton( - "TestRowClientButton", // ID кнопки - "ics-wolv-toolbar-button ics-wolv-toolbar-button-icon wolv-test-row-client-button", // CSS-класс - "Тестовая клиентская кнопка в строке", // Текст подсказки - "RowBtnClickAlert", // Название JS-функции. - // В принципе, вариант alert(\"Нажата пользовательская кнопка в строке с клиентским обработчиком\"); - // тоже прокатывает, но при более сложных обработчиках может работать некорректно. - // Рекомендуется передавать имя функции и описывать её отдельно! - string.Empty); // Параметры, передаваемые в функцию RowBtnClickAlert. - ... -} -``` +--- +title: Добавление кнопки в тулбар или в строки WebObjectListView +sidebar: flexberry-aspnet_sidebar +keywords: Flexberry ASP-NET +toc: true +permalink: ru/fa_wolv-add-button.html +lang: ru +--- + +## Добавление кнопок в тулбар WOLV + +Чтобы добавить кнопку в Toolbar WOLV необходимо воспользоваться методом `AddImageButton(...)` списка. +Однако, прежде чем добавлять кнопку в Toolbar, стоит определиться, какой обработчик будет у данной кнопки: + +* Серверный +* Клиентский +* Серверный и клиентский. + +### Серверный обработчик + +Если обработчик должен быть серверным, то необходимо воспользоваться следующей перегрузкой метода `AddImageButton`: + +```csharp +/// +/// Метод для добавления пользовательской кнопки в тулбар с возможностью установки +/// серверного обработчика. +/// +/// Серверный идентификатор кнопки. +/// CSS класс, который применится к кнопке. +/// Текст подсказки к кнопке. +/// Серверный обработчик нажатия кнопки. +public void AddImageButton(string id, string cssClass, string alternateText, ToolBarBtnEventHandler clickHandler) +``` + +Как можно заметить, в метод передаётся ID кнопки, CSS-класс, текст всплывающей подсказки, а также серверный обработчик нажатия следующего вида: + +```csharp +public delegate void ToolBarBtnEventHandler(LinkButton sender, ToolBarBtnEventArgs eventArgs); +``` + +#### ToolBarBtnEventArgs + +`ToolBarBtnEventArgs` - аргументы, передаваемые в серверный обработчик нажатия кнопки в Toolbar'e WOLV. + +Информация, которую можно получить из `ToolBarBtnEventArgs`: + +| Название | Описание | +| -------- | -------- | +| `List PrimaryKeys` | Список ключей объектов, выделенных в списке. __Важно: если установлена опция "Выделить всё на всех страницах", то вернётся пустой список__. | +| `bool IsAllSelected` | Установлена ли опция "Выделить всё на всех страницах". | +| `WebObjectListView WOLV` | Экземпляр списка, на Toolbar'e которого была нажата кнопка. | +| `Function LimitFunction` | Ограничивающая функция, наложенная на список. | + +#### Пример использования + +```csharp +protected override void Preload() +{ + ... + WebObjectListView1.AddImageButton( + "TestToolbarServerButton", // ID кнопки + "wolv-test-toolbar-server-button", // CSS-Класс + "Тестовая серверная кнопка тулбара", // Текст всплывающей подсказки + CustomToolbarButtonClickHandler); // Обработчик + ... +} +... + +private void CustomToolbarButtonClickHandler(object sender, ToolBarBtnEventArgs eventArgs) +{ + TestToolbarButtonLabel.Visible = true; + + // Проверка свойства Wolv аргументов события. + if (eventArgs.Wolv != WebObjectListView1) + { + throw new Exception("Экземпляр WOLV в обработчике нажатия кнопки тулбара задан неверно."); + } + + // Проверка свойства PrimaryKeys. + if (eventArgs.PrimaryKeys.Count > 0) + { + var objects = eventArgs.PrimaryKeys.Select(x => new Город { __PrimaryKey = Guid.Parse(x) }) + .Cast().ToArray(); + IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. + IDataService ds = mainUnityContainer.Resolve(); + ds.LoadObjects(objects, Город.Views.ГородL, true); + + SelectedCitiesLabel.Visible = SelectedCitiesList.Visible = true; + foreach (var obj in objects) + { + SelectedCitiesList.Controls.Add(new HtmlGenericControl("li") { InnerText = ((Город)obj).Наименование }); + } + } + + // Проверка свойства IsAllSelected. + AllIsSelectedLabel.Visible = eventArgs.IsAllSelected; +} +``` + +### Клиентский обработчик + +Если обработчик должен быть клиентским, необходимо воспользоваться следующей перегрузкой метода `AddImageButton`: + +```csharp +/// +/// Метод для добавления пользовательской кнопки в тулбар с возможностью установки +/// клиентского обработчика. +/// +/// Серверный идентификатор кнопки. +/// CSS класс, который применится к кнопке. +/// Текст подсказки к кнопке. +/// Наименование JS функции в глобальном объекте - клиентского обработчика нажатия кнопки. +/// Дополнительные параметры для JS обработчика. +public void AddImageButton(string id, string cssClass, string alternateText, string clientClickHandler, string clientClickAddParams) +``` + +Кроме ID, CSS-класса и текста всплывающей подсказки в метод также передается имя JS-функции, а также параметры, которые стоит передать в эту функцию. + +{% include note.html content="Передаётся имя JS-функции, а не её код." %} + +#### Пример использования + +```csharp +protected override void Preload() +{ + ... + WebObjectListView1.AddImageButton( + "TestToolbarClientButton", // ID кнопки + "wolv-test-toolbar-client-button", // CSS-класс + "Тестовая клиентская кнопка тулбара", // Текст подсказки + "ToolbarBtnClickAlert", // Название JS-функции. + // В принципе, вариант alert(\"Нажата пользовательская кнопка тулбара с клиентским обработчиком\"); + // тоже прокатывает, но при более сложных обработчиках может работать некорректно. + // Рекомендуется передавать имя функции и описывать её отдельно! + string.Empty); // Параметры, передаваемые в функцию ToolbarBtnClickAlert. + ... +} +``` + +### Серверный и клиентский обработчик + +Чтобы добавить кнопку с одновременно и серверным, и клиентским обработчиком, необходимо воспользоваться следующей перегрузкой метода `AddImageButton(...)`: + +```csharp +/// +/// Добавление кнопки на тулбар. +/// +/// Кнопка для добавления. +public void AddImageButton(LinkButton lb) +``` + +При использовании этого метода важно понимать следующее: + +1. Использовать этот метод необходимо только тогда, когда другие методы не подходят. +2. Вся настройка кнопки (включая внешний вид и стили) ложится на прикладного разработчика. + +#### Пример использования + +```csharp +var twoHandlersButton = new LinkButton +{ + OnClientClick = "alert('Сработал серверный обработчик кнопки с 2 обработчиками.');", + ID = "TwoHandlersButton", + CssClass = "ics-wolv-toolbar-button wolv-test-toolbar-client-server-button", +}; +twoHandlersButton.Click += CustomToolbarButtonClickHandler1; +twoHandlersButton.ToolTip = "Кнопка с двумя обработчиками."; +WebObjectListView1.AddImageButton(twoHandlersButton); +``` + +## Добавление кнопок в строки WOLV + +Чтобы добавить кнопку в Toolbar WOLV необходимо воспользоваться методом `AddImageButtonToRow(...)` списка. + +Однако, прежде чем добавлять кнопку в Toolbar, стоит определиться, какой обработчик будет у данной кнопки: + +* Серверный +* Клиентский. + +### Серверный обработчик + +Если обработчик должен быть серверным, то необходимо воспользоваться следующей перегрузкой метода `AddImageButtonToRow`: + +```csharp +/// +/// Добавить кнопку в каждую строку +/// +/// ID кнопки (прибавится индекс строки) +/// Класс контрола +/// Подпись +/// Серверное событие, которое придёт при нажатии +/// PrimaryKey объекта в строке можно получить так: +/// primaryKey = (sender as ImageButton).Attributes["pk"]; +/// +public void AddImageButtonToRow(string id, string cssClass, string alternateText, ToolBarBtnEventHandler clickHandler) +``` + +Как и в случае с добавлением серверной кнопки на Toolbar, в метод передаётся ID кнопки, CSS-класс, текст всплывающей подсказки, а также серверный обработчик нажатия следующего вида: + +```csharp +public delegate void ToolBarBtnEventHandler(LinkButton sender, ToolBarBtnEventArgs eventArgs); +``` + +#### ToolBarBtnEventArgs + +Аналогично EventArgs'ам Toolbar'a. + +#### Пример использования + +```csharp +protected override void Preload() +{ + ... + WebObjectListView1.AddImageButtonToRow( + "TestRowServerButton", // ID кнопки + "ics-wolv-toolbar-button ics-wolv-toolbar-button-icon wolv-test-row-server-button", // CSS-класс + "Тестовая серверная кнопка в строке", // Текст всплывающей подсказки + CustomToolbarButtonClickHandler); // Серверный обработчик нажатия + ... +} + +... + +private void CustomToolbarButtonClickHandler(object sender, ToolBarBtnEventArgs eventArgs) +{ + TestToolbarButtonLabel.Visible = true; + + // Проверка свойства Wolv аргументов события. + if (eventArgs.Wolv != WebObjectListView1) + { + throw new Exception("Экземпляр WOLV в обработчике нажатия кнопки тулбара задан неверно."); + } + + // Проверка свойства PrimaryKeys. + if (eventArgs.PrimaryKeys.Count > 0) + { + var objects = eventArgs.PrimaryKeys.Select(x => new Город { __PrimaryKey = Guid.Parse(x) }) + .Cast().ToArray(); + IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. + IDataService ds = mainUnityContainer.Resolve(); + ds.LoadObjects(objects, Город.Views.ГородL, true); + + SelectedCitiesLabel.Visible = SelectedCitiesList.Visible = true; + foreach (var obj in objects) + { + SelectedCitiesList.Controls.Add(new HtmlGenericControl("li") { InnerText = ((Город)obj).Наименование }); + } + } + + // Проверка свойства IsAllSelected. + AllIsSelectedLabel.Visible = eventArgs.IsAllSelected; +} +``` + +### Клиентский обработчик + +Если обработчик должен быть клиентским, необходимо воспользоваться следующей перегрузкой метода `AddImageButton`: + +```csharp +/// +/// Добавить кнопку в каждую строку +/// +/// ID кнопки (прибавится индекс строки) +/// Класс контрола +/// Подпись +/// Имя клиентской функции, которая будет вызвана при клике +/// Дополнительные параметры, которые передадутся в клиентскую функцию +public void AddImageButtonToRow(string id, string cssClass, string alternateText, string clientClickHandler, string clientClickAddParams) +``` + +Кроме ID, CSS-класса и текста всплывающей подсказки в метод также передается имя JS-функции, а также параметры, которые стоит передать в эту функцию. + +{% include note.html content="Передаётся имя JS-функции, а не её код." %} + +#### Пример использования + +```csharp +protected override void Preload() +{ + ... + WebObjectListView1.AddImageButton( + "TestRowClientButton", // ID кнопки + "ics-wolv-toolbar-button ics-wolv-toolbar-button-icon wolv-test-row-client-button", // CSS-класс + "Тестовая клиентская кнопка в строке", // Текст подсказки + "RowBtnClickAlert", // Название JS-функции. + // В принципе, вариант alert(\"Нажата пользовательская кнопка в строке с клиентским обработчиком\"); + // тоже прокатывает, но при более сложных обработчиках может работать некорректно. + // Рекомендуется передавать имя функции и описывать её отдельно! + string.Empty); // Параметры, передаваемые в функцию RowBtnClickAlert. + ... +} +``` diff --git a/pages/products/flexberry-aspnet/controls/wolv/fa_wolv-events.ru.md b/pages/products/flexberry-aspnet/controls/wolv/fa_wolv-events.ru.md index 6d666c343..1f504e898 100644 --- a/pages/products/flexberry-aspnet/controls/wolv/fa_wolv-events.ru.md +++ b/pages/products/flexberry-aspnet/controls/wolv/fa_wolv-events.ru.md @@ -1,296 +1,300 @@ ---- -title: События WebObjectListView -sidebar: flexberry-aspnet_sidebar -keywords: Flexberry ASP-NET -toc: true -permalink: ru/fa_wolv-events.html -lang: ru ---- - -Все аргументы событий [WebObjectListView](fa_web-object-list-view.html) наследуются от базового: - -```csharp -/// -/// Тип аргумента для событий WOLV. -/// -public class WolvEventArgs : CancelEventArgs -{ -} -``` - -## Список событий - -| Событие | Описание | -| ------- | -------- | -| `ObjectAdding` | Переход на форму создания объекта. | -| `ObjectEditing` | Переход на форму редактирования объекта. | -| `ObjectPrototyping` | Переход на форму прототипирования объекта. | -| `ObjectDeleting` | Удаление объекта началось. Событие будет вызываться для каждого удаляемого объекта. | -| `ObjectsDeleted` | Объекты удалились. Нельзя генерировать событие удаление для каждого объекта. | - -* Есть возможность настроить своё сообщение для пользователей после удаления объекта. Для формирования сообщения можно использовать список удаленных объектов и - список объектов, которые не удалось удалить. -* Также есть возможность передавать статус удаления меду событиями начала удаления и окончания удаления. - -## Аргументы событий - -У событий `ObjectEditing` и `ObjectPrototyping` в аргументах содержится первичный ключ объекта данных - `DataObjectPrimaryKey`. - -Через аргументы события `ObjectDeleting` можно получить к удаляемому объекту данных - `DataObj`, а так же изменять его. - -Аргументы события `ObjectsDeleted` позволяют редактировать или очищать сообщение пользователю - `UserMessage`. - -Для хранения прикладных метаданных между событием `ObjectDeleting` и событием `ObjectsDeleted` используются `DeletingState` и `DeletedState`, доступные через аргументы этих событий. - -## Отмена событий - -Любое событие можно отменить, установив свойство у аргументов `Cancel = true`, т.к. все аргументы наследуются от `CancelEventArgs`. - -Если произошло исключение при удалении объекта, то его можно обработать подписавшись на событие `ExceptionThrown`. - -## Собственный обработчик события `ObjectDeleting` - -Если реализуется собственный обработчик `ObjectDeleting` и устанавливается свойство у аргументов `Cancel = true`, то нужно в обработчике события `ObjectsDeleted` очистить или изменить на своё сообщение пользователю, которое хранится `args.UserMessage`. Иначе появится сообщение "Не удалено объектов: 1, т.к. некоторые объекты были заблокированы.", даже если объекты успешно удалены. - -## Пример ручной обработки события `ObjectDeleting` для обработки [каскадного удаления объектов](fo_cascade-delete.html) - -Концепция обработки событий: - -1. Подписаться на событие `ObjectDeleting`. -2. Написать обработчик, чтобы обработать каскадное удаление объектов, связанных с удаляемым. -3. Написать код бизнес-сервера, который будет сообщать обработчику об объектах, связанных с удаляемым. -4. Если таковые имеются, то запросить у пользователя разрешение на удаление связанных объектов (показав ему какие именно объекты будут удалены). -5. Если пользователь, разрешит каскадное удаление, то выполнить его. - -### Первый этап. Подписка на событие - -__Первый вариант.__ Подписаться статично (в разметке страницы, содержащей [WebObjectListView](fa_web-object-list-view.html). Пусть она называется `wolv_page.aspx`). - -```xml -<%-- Разметка из wolv_page.aspx --%>; -; -``` - -__Второй вариант.__ Подписаться из кода (в code-behind страницы, содержащей WOLV. Пусть файл с кодом называется `wolv_page.aspx.cs`). - -```csharp -// Код из wolv_page.aspx.cs -protected override void Preload() -{ - WebObjectListView1.ObjectDeleting += WebObjectListView1_ObjectDeleting; -} -``` - -{% include note.html content="При подписке на событие из кода, студия предложит автоматическую генерацию обработчика события. Если нажать клавишу `Tab` после того как -напечатано +=, то сгенерируется имя обработчика `WebObjectListView1_ObjectDeleting.` - -Если еще раз нажать клавишу `Tab`, будет сгенерирован шаблон обработчика: - -```csharp -protected void WebObjectListView1_ObjectDeleting(WebObjectListView sender, WolvEventArgs args) -``` -" %} - -### Второй этап. Обработка события - -```csharp -// Код из wolv_page.aspx.cs - -// Колекция объектов в формате [{objectPK: Строковое представление первичного ключа удаляемого адреса, confirmMessage: Текст сообщения о ссылающихся, на адрес, объектах}, ...] -private List _deletingObjectsCollection = new List(); - -// Данный обработчик будет последовательно вызван для каждого объекта, выбранного на удаление. -protected void WebObjectListView1_ObjectDeleting(WebObjectListView sender, WolvObjectDeletingEventArgs args) -{ - // Помечаем пришедший объект на удаление (в данном примере это будет адрес медицинского учреждения). - args.DataObj.SetStatus(ICSSoft.STORMNET.ObjectStatus.Deleted); - try - { // Пытаемся удалить (дальнейшая обработка происходит в Бизнес-сервере АдресБС.cs). - // Если во время удаления произойдет ошибка, мы сможем ее обработать в блоке catch. - // Если АдресБС.cs найдет учреждения, ссылающиеся на удаляемый адрес, он кинет ConfirmAdresDeletingException. - ICSSoft.STORMNET.Business.DataServiceProvider.DataService.UpdateObject(args.DataObj); - } - // Обрабатываем исключение бизнес-сервера - catch (ConfirmAdresDeletingException ex) - { - // Если мы попали в этот участок кода, значит были обнаружены объекты ссылающиеся на удаляемый адрес. - // Требуется подтверждение каскадного удаления. - // Запоминаем информацию о ссылках на удаляемый адрес. После перезагрузки страницы, её заберёт клиентский код. - // objectPK - первичный ключ ссылающегося объекта, confirmMessage - сообщение об этом объекте, сформированное в бизнес-сервере. - _deletingObjectsCollection.Add(new { objectPK = args.DataObj.__PrimaryKey.ToString(), confirmMessage = ex.Message }); - } - //Отменяем дальнейшее выполнение удаления WOLV-ом, т.к. мы уже выполнили его руками. - //Если этого не сделать, то код на бизнес-сервере выполнится повторно. - args.Cancel = true; -} - -// Возвращает сериализованную строку JSON формата вида "[{"objectPK": "Строковое представление первичного ключа удаляемого адреса", "confirmMessage": "Текст сообщения о ссылающихся, на адрес, объектах"}, ...]". -public string DeletingObjects -{ - get - { - //JavaScriptSerializer находится в пространстве имен System.Web.Script.Serialization; - JavaScriptSerializer serializer = new JavaScriptSerializer(); - //Экранируем кавычки - return serializer.Serialize(_deletingObjectsCollection).Replace("\"", "\\\""); - } -} -``` - -### Третий этап. Получение в бизнес-сервере информации о связанных объектах - -```csharp -//Код из АдресБС.cs -public virtual ICSSoft.STORMNET.DataObject[] OnUpdateАдрес(IIS.MedicalInstitutionsGuide.Адрес UpdatedObject) -{ - // *** Start programmer edit section *** (OnUpdateАдрес) - //На случай, если обработка прервётся, возвращаем пустой массив DataObject[] - DataObject[] result = new DataObject[0]; - - if (UpdatedObject.GetStatus() == ObjectStatus.Deleted) - { - //Получим список учреждений ссылающихся на удаляемый адрес - var ds = (SQLDataService)DataServiceProvider.DataService; - МедицинскоеУчреждение[] mil = ds.Query<МедицинскоеУчреждение>(МедицинскоеУчреждение.Views.MIG_МедицинскоеУчреждениеE) - .Where(o => o.Адрес.__PrimaryKey == UpdatedObject.__PrimaryKey) - .ToArray(); - //Если список не пуст, значит потребуется каскадное удаление - //Нужно проверить дал ли пользователь подтверждение, а если еще - нет, то запросить его - if (mil.Length > 0) - { - //Если пользователь подтвердил каскадное удаление, то в DynamicProperties объекта должен находится флаг, по ключу "DeletingAllowed" - if (UpdatedObject.DynamicProperties.ContainsKey("DeletingAllowed")) - { - //Помечаем учреждения на удаление - foreach (МедицинскоеУчреждение mi in mil) - { - mi.SetStatus(ObjectStatus.Deleted); - } - //Возвращаем удаляемые учреждения, чтобы они были удалены в этой же транзакции - result = mil; - } - else - { - //Необходимо запросить у пользователя подтверждение на каскадное удаление учреждений, вслед за их адресом - //Формируем строку с названиями учреждений - string referencedObjects = String.Join(", ", mil.Select(o => String.Format("'{0}'", o.Название))); - //Прерываем удаление, отправив в обработчик удаления, сообщения о ссылающихся объектах - //Метод UpdatedObject.ToString(true) просто возвращает строку с адресом, например "Россия, Пермский край, Пермь, Братьев Игнатовых, 2" - throw new MIG_ConfirmAdresDeletingException(String.Format("Вы уверены, что хотите удалить адрес: '{0}'? На него ссылаются следующие медицинские учреждения: {1}. - Они так же будут удалены вместе с информацией об их телефонах и расходах.", - UpdatedObject.ToString(true), - referencedObjects)); - } - } - } - return result; - // *** End programmer edit section *** (OnUpdateАдрес) -} -``` - -### Четвертый этап. Запрос подтверждения на каскадное удаление объектов - -Запрос подтверждения при помощи [JavaScript API](fa_js-api-core.html): - -```javascript -//Код из wolv_page.aspx -//wiki запрещает тэг SCRIPT-а, поэтому перед ним стоит подчеркивание, в реальном коде его быть не должно. - - <_script type="text/javascript"> - //Клиенская обработка каскадного удаления адресов и ссылающихся, на них, объектов - $(document).ready(function () { - //Забираем с сервера (через публичное свойство DeletingObjects)сериализованную строку JSON формата вида - //"[{"objectPK": "Строковое представление первичного ключа удаляемого адреса", - // "confirmMessage": "Текст сообщения о ссылающихся, на адрес, объектах"}, ...]" и десериализуем её - var deletingObjects = $.parseJSON("<%=DeletingObjects%>"); - //Выполняем обработку, только если хотя бы для одного адреса требуется каскадное удаление - if (deletingObjects.length > 0) { - //Строка для сообщения пользователю - var confirmMessage = ""; - //Строка JSON формата для первичных ключей удаляемых адресов (для их передачи на сервер, в случае подтверждения удаления) - var deletingObjectsPK = ""; - var lastIndex = deletingObjects.length - 1; - //Формируем строки - for (var i = 0; i < deletingObjects.length; i++) { - confirmMessage = confirmMessage + (i + 1) + "). " + deletingObjects[i].confirmMessage + "\n"; - deletingObjectsPK = deletingObjectsPK + "\"" + deletingObjects[i].objectPK + "\""; - if (i < lastIndex) { - deletingObjectsPK = deletingObjectsPK + ", "; - } - } - deletingObjectsPK = "[" + deletingObjectsPK + "]"; - //Отображаем окно подтверждения - $.ics.dialog.confirm({ - message: confirmMessage, - title: 'Подтверждение каскадного удаления связанных объектов', - okButtonText: "Всё равно удалить", - cancelButtonText: "Отменить удаление", - callback: function (res) { - if (res) { - //При нажатии OK. - //Инициируем PostBack, передав, в качестве аргумента, - //строку JSON формата с первичными ключами удалямых адресов. - //'confirmDeletingOkBtn' - имя кнопки на окне подтверждения, которая инициирует PostBack. - __doPostBack('confirmDeletingOkBtn', deletingObjectsPK); - } else { - //При нажати Cancel. - alert("Каскадное удаление отменено."); - } - } - }); - } - }); - - -``` - -Пользователю будет выдано следующее окно подтверждения: - -![](/images/pages/products/flexberry-aspnet/controls/wolv/confirm-cascade-deleting.png) - -### Пятый этап. Выполнить каскадное удаление объектов, если пользователь дал согласие - -```csharp -// Код из wolv_page.aspx.cs -protected override void Preload() -{ - // *** Start programmer edit section *** (PostBack handling) - if (Page.IsPostBack) - { - //Обрабатываем случай, когда PostBack произошел при подтверждении, пользователем, - //каскадного удаления выбранных адресов и ссылающихся, на них, объектов. - - //Получаем имя объекта вызвавшего PostBack - string targetID = Request.Form["__EVENTTARGET"]; - if (!String.IsNullOrEmpty(targetID)) - { - //Если объект - это кнопка "OK" окна подтверждения - if (targetID.Equals("confirmDeletingOkBtn")) - { - //Получаем строку JSON формата с первичными ключами удаляемых адресов - string argument = Request.Form["__EVENTARGUMENT"]; - //Выполняем десериализацию строки - JavaScriptSerializer serializer = new JavaScriptSerializer(); - List deletingObjectsPK = serializer.Deserialize>(argument); - //Формируем массив удаляемых адресов - DataObject[] deletingAdreses = deletingObjectsPK.Select(pk => - { - //Создаем объект класса "Адрес" с нужным первичным ключом - Адрес deletingAdres = new Адрес(); - deletingAdres.SetExistObjectPrimaryKey(new Guid(pk)); - //Подтверждаем каскадное удаление объектов, ссылающихся на этот адрес - //по наличию, в DynamicProperties, ключа "DeletingAllowed", бизнес-сервер поймёт, что каскадное удаление разрешено - deletingAdres.DynamicProperties.Add("DeletingAllowed", true); - //Помечаем адрес на удаление - deletingAdres.SetStatus(ObjectStatus.Deleted); - //Добавляем в массив - return deletingAdres; - }).ToArray<Адрес>(); - //Удаляем. (Дальнейшая обработка происходит в АдресБС) - DataServiceProvider.DataService.UpdateObjects(ref deletingAdreses); - } - } - } - // *** End programmer edit section *** (PostBack handling) -} -``` +--- +title: События WebObjectListView +sidebar: flexberry-aspnet_sidebar +keywords: Flexberry ASP-NET +toc: true +permalink: ru/fa_wolv-events.html +lang: ru +--- + +Все аргументы событий [WebObjectListView](fa_web-object-list-view.html) наследуются от базового: + +```csharp +/// +/// Тип аргумента для событий WOLV. +/// +public class WolvEventArgs : CancelEventArgs +{ +} +``` + +## Список событий + +| Событие | Описание | +| ------- | -------- | +| `ObjectAdding` | Переход на форму создания объекта. | +| `ObjectEditing` | Переход на форму редактирования объекта. | +| `ObjectPrototyping` | Переход на форму прототипирования объекта. | +| `ObjectDeleting` | Удаление объекта началось. Событие будет вызываться для каждого удаляемого объекта. | +| `ObjectsDeleted` | Объекты удалились. Нельзя генерировать событие удаление для каждого объекта. | + +* Есть возможность настроить своё сообщение для пользователей после удаления объекта. Для формирования сообщения можно использовать список удаленных объектов и + список объектов, которые не удалось удалить. +* Также есть возможность передавать статус удаления меду событиями начала удаления и окончания удаления. + +## Аргументы событий + +У событий `ObjectEditing` и `ObjectPrototyping` в аргументах содержится первичный ключ объекта данных - `DataObjectPrimaryKey`. + +Через аргументы события `ObjectDeleting` можно получить к удаляемому объекту данных - `DataObj`, а так же изменять его. + +Аргументы события `ObjectsDeleted` позволяют редактировать или очищать сообщение пользователю - `UserMessage`. + +Для хранения прикладных метаданных между событием `ObjectDeleting` и событием `ObjectsDeleted` используются `DeletingState` и `DeletedState`, доступные через аргументы этих событий. + +## Отмена событий + +Любое событие можно отменить, установив свойство у аргументов `Cancel = true`, т.к. все аргументы наследуются от `CancelEventArgs`. + +Если произошло исключение при удалении объекта, то его можно обработать подписавшись на событие `ExceptionThrown`. + +## Собственный обработчик события `ObjectDeleting` + +Если реализуется собственный обработчик `ObjectDeleting` и устанавливается свойство у аргументов `Cancel = true`, то нужно в обработчике события `ObjectsDeleted` очистить или изменить на своё сообщение пользователю, которое хранится `args.UserMessage`. Иначе появится сообщение "Не удалено объектов: 1, т.к. некоторые объекты были заблокированы.", даже если объекты успешно удалены. + +## Пример ручной обработки события `ObjectDeleting` для обработки [каскадного удаления объектов](fo_cascade-delete.html) + +Концепция обработки событий: + +1. Подписаться на событие `ObjectDeleting`. +2. Написать обработчик, чтобы обработать каскадное удаление объектов, связанных с удаляемым. +3. Написать код бизнес-сервера, который будет сообщать обработчику об объектах, связанных с удаляемым. +4. Если таковые имеются, то запросить у пользователя разрешение на удаление связанных объектов (показав ему какие именно объекты будут удалены). +5. Если пользователь, разрешит каскадное удаление, то выполнить его. + +### Первый этап. Подписка на событие + +__Первый вариант.__ Подписаться статично (в разметке страницы, содержащей [WebObjectListView](fa_web-object-list-view.html). Пусть она называется `wolv_page.aspx`). + +```xml +<%-- Разметка из wolv_page.aspx --%>; +; +``` + +__Второй вариант.__ Подписаться из кода (в code-behind страницы, содержащей WOLV. Пусть файл с кодом называется `wolv_page.aspx.cs`). + +```csharp +// Код из wolv_page.aspx.cs +protected override void Preload() +{ + WebObjectListView1.ObjectDeleting += WebObjectListView1_ObjectDeleting; +} +``` + +> При подписке на событие из кода, студия предложит автоматическую генерацию обработчика события. Если нажать клавишу `Tab` после того как +напечатано +=, то сгенерируется имя обработчика `WebObjectListView1_ObjectDeleting.` + +Если еще раз нажать клавишу `Tab`, будет сгенерирован шаблон обработчика: + +```csharp +protected void WebObjectListView1_ObjectDeleting(WebObjectListView sender, WolvEventArgs args) +``` + +### Второй этап. Обработка события + +```csharp +// Код из wolv_page.aspx.cs + +// Колекция объектов в формате [{objectPK: Строковое представление первичного ключа удаляемого адреса, confirmMessage: Текст сообщения о ссылающихся, на адрес, объектах}, ...] +private List _deletingObjectsCollection = new List(); + +// Данный обработчик будет последовательно вызван для каждого объекта, выбранного на удаление. +protected void WebObjectListView1_ObjectDeleting(WebObjectListView sender, WolvObjectDeletingEventArgs args) +{ + // Помечаем пришедший объект на удаление (в данном примере это будет адрес медицинского учреждения). + args.DataObj.SetStatus(ICSSoft.STORMNET.ObjectStatus.Deleted); + try + { // Пытаемся удалить (дальнейшая обработка происходит в Бизнес-сервере АдресБС.cs). + // Если во время удаления произойдет ошибка, мы сможем ее обработать в блоке catch. + // Если АдресБС.cs найдет учреждения, ссылающиеся на удаляемый адрес, он кинет ConfirmAdresDeletingException. + IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. + IDataService ds = mainUnityContainer .Resolve(); + ICSSoft.STORMNET.Business.ds.UpdateObject(args.DataObj); + } + // Обрабатываем исключение бизнес-сервера + catch (ConfirmAdresDeletingException ex) + { + // Если мы попали в этот участок кода, значит были обнаружены объекты ссылающиеся на удаляемый адрес. + // Требуется подтверждение каскадного удаления. + // Запоминаем информацию о ссылках на удаляемый адрес. После перезагрузки страницы, её заберёт клиентский код. + // objectPK - первичный ключ ссылающегося объекта, confirmMessage - сообщение об этом объекте, сформированное в бизнес-сервере. + _deletingObjectsCollection.Add(new { objectPK = args.DataObj.__PrimaryKey.ToString(), confirmMessage = ex.Message }); + } + //Отменяем дальнейшее выполнение удаления WOLV-ом, т.к. мы уже выполнили его руками. + //Если этого не сделать, то код на бизнес-сервере выполнится повторно. + args.Cancel = true; +} + +// Возвращает сериализованную строку JSON формата вида "[{"objectPK": "Строковое представление первичного ключа удаляемого адреса", "confirmMessage": "Текст сообщения о ссылающихся, на адрес, объектах"}, ...]". +public string DeletingObjects +{ + get + { + //JavaScriptSerializer находится в пространстве имен System.Web.Script.Serialization; + JavaScriptSerializer serializer = new JavaScriptSerializer(); + //Экранируем кавычки + return serializer.Serialize(_deletingObjectsCollection).Replace("\"", "\\\""); + } +} +``` + +### Третий этап. Получение в бизнес-сервере информации о связанных объектах + +```csharp +//Код из АдресБС.cs +public virtual ICSSoft.STORMNET.DataObject[] OnUpdateАдрес(IIS.MedicalInstitutionsGuide.Адрес UpdatedObject) +{ + // *** Start programmer edit section *** (OnUpdateАдрес) + //На случай, если обработка прервётся, возвращаем пустой массив DataObject[] + DataObject[] result = new DataObject[0]; + + if (UpdatedObject.GetStatus() == ObjectStatus.Deleted) + { + //Получим список учреждений ссылающихся на удаляемый адрес + IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. + IDataService ds = mainUnityContainer.Resolve(); + МедицинскоеУчреждение[] mil = ds.Query<МедицинскоеУчреждение>(МедицинскоеУчреждение.Views.MIG_МедицинскоеУчреждениеE) + .Where(o => o.Адрес.__PrimaryKey == UpdatedObject.__PrimaryKey) + .ToArray(); + //Если список не пуст, значит потребуется каскадное удаление + //Нужно проверить дал ли пользователь подтверждение, а если еще - нет, то запросить его + if (mil.Length > 0) + { + //Если пользователь подтвердил каскадное удаление, то в DynamicProperties объекта должен находится флаг, по ключу "DeletingAllowed" + if (UpdatedObject.DynamicProperties.ContainsKey("DeletingAllowed")) + { + //Помечаем учреждения на удаление + foreach (МедицинскоеУчреждение mi in mil) + { + mi.SetStatus(ObjectStatus.Deleted); + } + //Возвращаем удаляемые учреждения, чтобы они были удалены в этой же транзакции + result = mil; + } + else + { + //Необходимо запросить у пользователя подтверждение на каскадное удаление учреждений, вслед за их адресом + //Формируем строку с названиями учреждений + string referencedObjects = String.Join(", ", mil.Select(o => String.Format("'{0}'", o.Название))); + //Прерываем удаление, отправив в обработчик удаления, сообщения о ссылающихся объектах + //Метод UpdatedObject.ToString(true) просто возвращает строку с адресом, например "Россия, Пермский край, Пермь, Братьев Игнатовых, 2" + throw new MIG_ConfirmAdresDeletingException(String.Format("Вы уверены, что хотите удалить адрес: '{0}'? На него ссылаются следующие медицинские учреждения: {1}. + Они так же будут удалены вместе с информацией об их телефонах и расходах.", + UpdatedObject.ToString(true), + referencedObjects)); + } + } + } + return result; + // *** End programmer edit section *** (OnUpdateАдрес) +} +``` + +### Четвертый этап. Запрос подтверждения на каскадное удаление объектов + +Запрос подтверждения при помощи [JavaScript API](fa_js-api-core.html): + +```javascript +//Код из wolv_page.aspx +//wiki запрещает тэг SCRIPT-а, поэтому перед ним стоит подчеркивание, в реальном коде его быть не должно. + + <_script type="text/javascript"> + //Клиенская обработка каскадного удаления адресов и ссылающихся, на них, объектов + $(document).ready(function () { + //Забираем с сервера (через публичное свойство DeletingObjects)сериализованную строку JSON формата вида + //"[{"objectPK": "Строковое представление первичного ключа удаляемого адреса", + // "confirmMessage": "Текст сообщения о ссылающихся, на адрес, объектах"}, ...]" и десериализуем её + var deletingObjects = $.parseJSON("<%=DeletingObjects%>"); + //Выполняем обработку, только если хотя бы для одного адреса требуется каскадное удаление + if (deletingObjects.length > 0) { + //Строка для сообщения пользователю + var confirmMessage = ""; + //Строка JSON формата для первичных ключей удаляемых адресов (для их передачи на сервер, в случае подтверждения удаления) + var deletingObjectsPK = ""; + var lastIndex = deletingObjects.length - 1; + //Формируем строки + for (var i = 0; i < deletingObjects.length; i++) { + confirmMessage = confirmMessage + (i + 1) + "). " + deletingObjects[i].confirmMessage + "\n"; + deletingObjectsPK = deletingObjectsPK + "\"" + deletingObjects[i].objectPK + "\""; + if (i < lastIndex) { + deletingObjectsPK = deletingObjectsPK + ", "; + } + } + deletingObjectsPK = "[" + deletingObjectsPK + "]"; + //Отображаем окно подтверждения + $.ics.dialog.confirm({ + message: confirmMessage, + title: 'Подтверждение каскадного удаления связанных объектов', + okButtonText: "Всё равно удалить", + cancelButtonText: "Отменить удаление", + callback: function (res) { + if (res) { + //При нажатии OK. + //Инициируем PostBack, передав, в качестве аргумента, + //строку JSON формата с первичными ключами удалямых адресов. + //'confirmDeletingOkBtn' - имя кнопки на окне подтверждения, которая инициирует PostBack. + __doPostBack('confirmDeletingOkBtn', deletingObjectsPK); + } else { + //При нажати Cancel. + alert("Каскадное удаление отменено."); + } + } + }); + } + }); + + +``` + +Пользователю будет выдано следующее окно подтверждения: + +![confirm-cascade-deleting](/images/pages/products/flexberry-aspnet/controls/wolv/confirm-cascade-deleting.png) + +### Пятый этап. Выполнить каскадное удаление объектов, если пользователь дал согласие + +```csharp +// Код из wolv_page.aspx.cs +protected override void Preload() +{ + // *** Start programmer edit section *** (PostBack handling) + if (Page.IsPostBack) + { + //Обрабатываем случай, когда PostBack произошел при подтверждении, пользователем, + //каскадного удаления выбранных адресов и ссылающихся, на них, объектов. + + //Получаем имя объекта вызвавшего PostBack + string targetID = Request.Form["__EVENTTARGET"]; + if (!String.IsNullOrEmpty(targetID)) + { + //Если объект - это кнопка "OK" окна подтверждения + if (targetID.Equals("confirmDeletingOkBtn")) + { + //Получаем строку JSON формата с первичными ключами удаляемых адресов + string argument = Request.Form["__EVENTARGUMENT"]; + //Выполняем десериализацию строки + JavaScriptSerializer serializer = new JavaScriptSerializer(); + List deletingObjectsPK = serializer.Deserialize>(argument); + //Формируем массив удаляемых адресов + DataObject[] deletingAdreses = deletingObjectsPK.Select(pk => + { + //Создаем объект класса "Адрес" с нужным первичным ключом + Адрес deletingAdres = new Адрес(); + deletingAdres.SetExistObjectPrimaryKey(new Guid(pk)); + //Подтверждаем каскадное удаление объектов, ссылающихся на этот адрес + //по наличию, в DynamicProperties, ключа "DeletingAllowed", бизнес-сервер поймёт, что каскадное удаление разрешено + deletingAdres.DynamicProperties.Add("DeletingAllowed", true); + //Помечаем адрес на удаление + deletingAdres.SetStatus(ObjectStatus.Deleted); + //Добавляем в массив + return deletingAdres; + }).ToArray<Адрес>(); + //Удаляем. (Дальнейшая обработка происходит в АдресБС) + IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. + IDataService ds = mainUnityContainer.Resolve(); + ds.UpdateObjects(ref deletingAdreses); + } + } + } + // *** End programmer edit section *** (PostBack handling) +} +``` diff --git a/pages/products/flexberry-aspnet/controls/wolv/fa_wolv-export-excel.ru.md b/pages/products/flexberry-aspnet/controls/wolv/fa_wolv-export-excel.ru.md index eedf67d22..9a37a222a 100644 --- a/pages/products/flexberry-aspnet/controls/wolv/fa_wolv-export-excel.ru.md +++ b/pages/products/flexberry-aspnet/controls/wolv/fa_wolv-export-excel.ru.md @@ -1,131 +1,131 @@ ---- -title: Экспорт данных из WebObjectListView в Excel -sidebar: flexberry-aspnet_sidebar -keywords: Flexberry ASP-NET, Flexberry Reports, БД -toc: true -permalink: ru/fa_wolv-export-excel.html -lang: ru ---- - -## Выгрузка в Excel (инструкция для программиста) - -[WebObjectListView](fa_web-object-list-view.html) позволяет выгружать данные в формате Excel. - -Эта функция включается операцией: - -```csharp -/// -/// Вызывается самым первым в Page_Load. -/// -protected override void Preload() -{ - WebObjectListView1.Operations.ExportToExcel = true; -} -``` - -### Представление для экспорта - -Задать [представление](fd_view-definition.html), используемое по умолчанию для экспорта, можно из кода, установив поле `ExportView` у [WOLV](fa_web-object-list-view.html): - -```csharp -WebObjectListView1.ExportView = Клиент.View.КлиентExport; -``` - -### Выгрузка детейлов - -Выгрузка детейлов осуществляется в том случае, если они присутствуют в [представлении](fd_view-definition.html). Пользователь может настроить параметры детейлового столбца также, как и остальные свойства объекта. - -Существует 2 настройки на [web-форме редактирования](fa_editform.html) для управления выгрузкой детейлов. - -1. Поля детейлов в отдельные столбцы. -2. Детейлы в отдельные строки. - -* Если ни 1 из настроек не выставлена, то детейлы выгружаются в 1 ячейку в строку: - -| Аггрегатор | Детейл| -|------------|--------| -| Поле аггрегатора | Детейл: Поле 1го детейла; Детейл: Поле 2го детейла; Детейл: Поле 3го детейла;| - -* Если выставлена настройка `Поля детейлов в отдельные столбцы`, то детейлы выгружаются в 1 ячейку в столбец: - -| Аггрегатор | Детейл| -|------------|---------| -| Поле аггрегатора | Поле 1го детейла| -||Поле 2го детейла| -||Поле 3го детейла| - -* Если выставить обе настройки сразу, то каждый детейл будет выводиться в новую строку, а поля агрегатора с различных строк объединятся в 1 ячейку: - -![](/images/pages/products/flexberry-aspnet/controls/wolv/two-options.png) - -* Выставлять только настройку `Детейлы в отдельные строки`, пока бессмысллено, ведется доработка данной настройки. - -__Примечание__: если в представление у поля детейла не задан заголовок, то в качестве заголовка поля при выгрузке будет использоваться имя поля. - -### Сервис данных - -По умолчанию для выгрузки в Excel используется сервис данных `DataServiceProvider.DataService`. Если требуется задать другой, отдельный сервис данных для выгрузки в Excel, то это может быть сделано в `Web.config` путем регистрации сервиса под именем `ExcelExportDataService` в `Unity`. Пример конфигурации, чтобы для выгрузки в Excel использовался сервис данных `IcsharpSoft.STORMNET.Business.DRDataService`: - -```xml - - - - - - - -``` - -#### Огриничение на максимальное количество объектов - -Для настройки максимального количества экспортируемых объектов следует вопспользоваться параметром конфигурации `WOLVExportLimit`: - -```xml - - - - - - -``` - -Отрицательные значения параметра и 0 отключают ограничение на максимальное количество экспортируемых объектов. - -### Добавление таблицы для хранения настроек - -Чтобы добавить в базу данных таблицу для хранения пользовательских настроек, необходимо иметь структуру данных, используемую [UserSettingsService](fa_user-settings-service.html). Таблица генерируется автоматически. - -## Выгрузка в Excel (инструкция для пользователя) - -Для выгрузки данных из списка необходимо нажать на кнопку `Выгрузить в Excel` ![](/images/pages/products/flexberry-aspnet/controls/wolv/export-button.png) на панели инструментов, в открывшемся окне настроить формат выгружаемых данных и подтвердить выгрузку, нажав на кнопку `OK`. - -![](/images/pages/products/flexberry-aspnet/controls/wolv/export-form.png) - -На форме можно: - -* Указать видимость полей, установив или сняв флажок в левой части каждой строки. -* Указать направление сортировки (без сортировки, по возрастанию или по убыванию) для каждого столбца данных. -* Указать приоритет сортировки (если указана одна из сортировок) -* Указать название столбца данных -* Поменять порядок следования столбцов данных - * При помощи кнопок `вверх` и `вниз` в правой части каждой строки - * Или при помощи перетаскивания строк - -По умолчанию выгружаются все данные, содержащиеся в списке с учётом наложенных фильтров и сортировки. - -Если в списке выделить какие-либо записи при помощи галочек, то будут выгружаться только выбранные записи. - -Созданные настройки выгрузки можно сохранять для последующего применения. Настройки задаются отдельными пользователями и не могут быть опубликованы для других пользователей. - -Для создания настройки необходимо выбрать пункт меню `Создать набор полей для экспорта...`. В открывшемся окне необходимо произвести необходимую настройку, указать наименование настройки и нажать кнопку `Сохранить`. Сохраненные настройки доступны из меню списка. При выборе сохраненной настройки автоматически будет предложено сохранить Excel-файл. - -Отредактировать или удалить настройки можно при выборе соответствующего пункта меню. - -![](/images/pages/products/flexberry-aspnet/controls/wolv/export-menu.png) - -Файлы выгружаются в XML, интерпретируемый `Microsoft Excel`, расширение у файла выставлено как *.xls (стандартное расширение документов MS Excel). При открытии -полученного файла в Excel выведется предупреждение: - -![](/images/pages/products/flexberry-aspnet/controls/wolv/export-warning.png) - -{% include note.html content="Если авторизация выключена или не работает, то возможность создания настроек будет отключена." %} +--- +title: Экспорт данных из WebObjectListView в Excel +sidebar: flexberry-aspnet_sidebar +keywords: Flexberry ASP-NET, Flexberry Reports, БД +toc: true +permalink: ru/fa_wolv-export-excel.html +lang: ru +--- + +## Выгрузка в Excel (инструкция для программиста) + +[WebObjectListView](fa_web-object-list-view.html) позволяет выгружать данные в формате Excel. + +Эта функция включается операцией: + +```csharp +/// +/// Вызывается самым первым в Page_Load. +/// +protected override void Preload() +{ + WebObjectListView1.Operations.ExportToExcel = true; +} +``` + +### Представление для экспорта + +Задать [представление](fd_view-definition.html), используемое по умолчанию для экспорта, можно из кода, установив поле `ExportView` у [WOLV](fa_web-object-list-view.html): + +```csharp +WebObjectListView1.ExportView = Клиент.View.КлиентExport; +``` + +### Выгрузка детейлов + +Выгрузка детейлов осуществляется в том случае, если они присутствуют в [представлении](fd_view-definition.html). Пользователь может настроить параметры детейлового столбца также, как и остальные свойства объекта. + +Существует 2 настройки на [web-форме редактирования](fa_editform.html) для управления выгрузкой детейлов. + +1. Поля детейлов в отдельные столбцы. +2. Детейлы в отдельные строки. + +* Если ни 1 из настроек не выставлена, то детейлы выгружаются в 1 ячейку в строку: + +| Аггрегатор | Детейл| +|------------|--------| +| Поле аггрегатора | Детейл: Поле 1го детейла; Детейл: Поле 2го детейла; Детейл: Поле 3го детейла;| + +* Если выставлена настройка `Поля детейлов в отдельные столбцы`, то детейлы выгружаются в 1 ячейку в столбец: + +| Аггрегатор | Детейл| +|------------|---------| +| Поле аггрегатора | Поле 1го детейла| +||Поле 2го детейла| +||Поле 3го детейла| + +* Если выставить обе настройки сразу, то каждый детейл будет выводиться в новую строку, а поля агрегатора с различных строк объединятся в 1 ячейку: + +![two-options](/images/pages/products/flexberry-aspnet/controls/wolv/two-options.png) + +* Выставлять только настройку `Детейлы в отдельные строки`, пока бессмысллено, ведется доработка данной настройки. + +__Примечание__: если в представление у поля детейла не задан заголовок, то в качестве заголовка поля при выгрузке будет использоваться имя поля. + +### Сервис данных + +По умолчанию для выгрузки в Excel используется сервис данных `IDataService`. Если требуется задать другой, отдельный сервис данных для выгрузки в Excel, то это может быть сделано в `Web.config` путем регистрации сервиса под именем `ExcelExportDataService` в `Unity`. Пример конфигурации, чтобы для выгрузки в Excel использовался сервис данных `IcsharpSoft.STORMNET.Business.DRDataService`: + +```xml + + + + + + + +``` + +#### Огриничение на максимальное количество объектов + +Для настройки максимального количества экспортируемых объектов следует вопспользоваться параметром конфигурации `WOLVExportLimit`: + +```xml + + + + + + +``` + +Отрицательные значения параметра и 0 отключают ограничение на максимальное количество экспортируемых объектов. + +### Добавление таблицы для хранения настроек + +Чтобы добавить в базу данных таблицу для хранения пользовательских настроек, необходимо иметь структуру данных, используемую [UserSettingsService](fa_user-settings-service.html). Таблица генерируется автоматически. + +## Выгрузка в Excel (инструкция для пользователя) + +Для выгрузки данных из списка необходимо нажать на кнопку `Выгрузить в Excel` ![export-button](/images/pages/products/flexberry-aspnet/controls/wolv/export-button.png) на панели инструментов, в открывшемся окне настроить формат выгружаемых данных и подтвердить выгрузку, нажав на кнопку `OK`. + +![export-form](/images/pages/products/flexberry-aspnet/controls/wolv/export-form.png) + +На форме можно: + +* Указать видимость полей, установив или сняв флажок в левой части каждой строки. +* Указать направление сортировки (без сортировки, по возрастанию или по убыванию) для каждого столбца данных. +* Указать приоритет сортировки (если указана одна из сортировок) +* Указать название столбца данных +* Поменять порядок следования столбцов данных + * При помощи кнопок `вверх` и `вниз` в правой части каждой строки + * Или при помощи перетаскивания строк + +По умолчанию выгружаются все данные, содержащиеся в списке с учётом наложенных фильтров и сортировки. + +Если в списке выделить какие-либо записи при помощи галочек, то будут выгружаться только выбранные записи. + +Созданные настройки выгрузки можно сохранять для последующего применения. Настройки задаются отдельными пользователями и не могут быть опубликованы для других пользователей. + +Для создания настройки необходимо выбрать пункт меню `Создать набор полей для экспорта...`. В открывшемся окне необходимо произвести необходимую настройку, указать наименование настройки и нажать кнопку `Сохранить`. Сохраненные настройки доступны из меню списка. При выборе сохраненной настройки автоматически будет предложено сохранить Excel-файл. + +Отредактировать или удалить настройки можно при выборе соответствующего пункта меню. + +![export-menu](/images/pages/products/flexberry-aspnet/controls/wolv/export-menu.png) + +Файлы выгружаются в XML, интерпретируемый `Microsoft Excel`, расширение у файла выставлено как *.xls (стандартное расширение документов MS Excel). При открытии +полученного файла в Excel выведется предупреждение: + +![export-warning](/images/pages/products/flexberry-aspnet/controls/wolv/export-warning.png) + +> Если авторизация выключена или не работает, то возможность создания настроек будет отключена. diff --git a/pages/products/flexberry-aspnet/subsystems/audit/fa_audit-web-forms.ru.md b/pages/products/flexberry-aspnet/subsystems/audit/fa_audit-web-forms.ru.md index fb35a3ec6..f554d4e6a 100644 --- a/pages/products/flexberry-aspnet/subsystems/audit/fa_audit-web-forms.ru.md +++ b/pages/products/flexberry-aspnet/subsystems/audit/fa_audit-web-forms.ru.md @@ -1,85 +1,89 @@ ---- -title: Web-формы аудита -sidebar: flexberry-aspnet_sidebar -keywords: Flexberry ASP-NET, Flexberry Audit -toc: true -permalink: ru/fa_audit-web-forms.html -lang: ru ---- - -[Web-формы](fa_tech-forms-web.html) [аудита](fa_audit-web.html) были разработаны для отображения объектов, используемых [ICSSoft.STORMNET.Business.Audit.Audit](efs_i-audit.html). Формы расположены в сборке "ICSSoft.STORMNET.Web.AjaxControls.dll". - -Существуют также [win-формы аудита](efs_audit-win-forms.html). - -### Записеориентированные формы аудита - -Записеориентированные формы аудита отображают записи аудита примерно в том же виде, в каком они есть в БД. - -**Списковая форма** позволяет просматривать как аудит по всей системе в целом, так и по конкретному объекту. -Чтобы просматривать данные по всей системе, достаточно просто подключить форму AuditEntityL к проекту (~/Forms/Audit/AuditEntityL.aspx). -Для просмотра данных по конкретному объекту необходимо передать форме дополнительно параметр AuPK, где указан [первичный ключ объект](fo_primary-keys-objects.html), чей аудит необходимо отобразить. - -Например, адрес может быть следующим: http://some:1111/Forms/Audit/AuditEntityL.aspx?AuPK={1843fc3c-b4fc-4a37-bf6e-60a0ea84aead}. - -**[Форма редактирования](fa_editform.html)** позволяет просмотреть детальную информацию по конкретной записи аудита. На данной форме присутствует таблица, где представлена информация об изменении полей объекта при проведении аудируемой операции. -Отдельной строкой идёт изменение [первичного ключа объекта](fo_primary-keys-objects.html) (такая строка формируется при изменении детейла или мастера). Доступно два режима отображения этих строчек: они совсем не отображаются или они скрываются в древовидную структуру (второй вариант был реализован в [старой версии аудита](efs_audit.html)). По умолчанию реализуется первый вариант, но это можно изменить следующей инициализацией: - -```csharp -AuditService.Current.ShowPrimaryKey = true; -``` - -## Объектноориентированные формы аудита - -Объектноориентированные формы аудита ориентированы на отображение информации - -**Списковая форма** AuditEntityByObjectsL (~/Forms/Audit/AuditEntityByObjectsL.aspx) позволяет просматривать сведения по объектам, над которыми производились аудируемые действия. - -Форма содержит [следующие поля](fa_audit-web.html): - -* Редактирование - дата последнего изменения объекта (создание, изменение или удаление). -* Редактор - имя пользователя, который последний изменял объект. -* Тип объекта - тип аудируемого объекта. -* Идентификатор - идентификатор аудируемого объекта (обычно [первичный ключ](fo_primary-keys-objects.html)). -* Создание - дата создания объекта. -* Создатель - имя пользователя, который создал объект. - -Список по умолчанию отсортирован по дате "Редактирование" (сверху новые). - -**Форма редактирования** AuditEntityByObjectsE позволяет просмотреть детальную информацию по конкретному аудируемому объекту. - -Форма содержит [следующие поля](fa_audit-web.html): - -* Идентификатор - идентификатор аудируемого объекта (обычно [первичный ключ](fo_primary-keys-objects.html)). -* Тип объекта - тип аудируемого объекта. -* Создание - дата создания объекта. -* Создатель - имя пользователя, который создал объект. -* Редактирование - дата последнего изменения объекта (создание, изменение или удаление). -* Редактор - имя пользователя, который последний изменял объект. -* Список полей аудита: - * Время операции - время, когда поле объекта было изменено. - * Тип операции - тип операции, которой было изменено поле. - * Имя - имя пользователя, который совершил аудируемую операцию. - * Логин - логин пользователя, который совершил аудируемую операцию. - * Имя поля - отображаемое имя поля. - * Старое значение - старое значение поля. - * Новое значение - новое значение поля. - * Источник - источник аудируемой операции. - * Результат - итог выполнения операции (удалось ли зафиксировать операцию, был ли провал и др.). - -Список полей аудита отсортирован по времени операции (сверху новые). - -Чтобы отключить отображение записей, содержащих [первичные ключи](fo_primary-keys-objects.html) [мастеров](fd_master-association.html) и [детейлов](fo_detail-associations-properties.html), можно выполнить следующую настройку: - -```csharp -AuditService.Current.ShowPrimaryKey = false; -``` - -Если AuditService.Current.ShowPrimaryKey имеет значение true, то список изменений полей отображается [в виде иерархии](fa_wolv-hierarhy.html) аналогично тому, как это сделано в записеориентированных формах аудита. - -{% include warning.html content="При использовании веб-форм аудита необходимо в файле WebControlProvider.xml добавить следующую информацию:" %} - -```csharp - - - -``` +--- +title: Web-формы аудита +sidebar: flexberry-aspnet_sidebar +keywords: Flexberry ASP-NET, Flexberry Audit +toc: true +permalink: ru/fa_audit-web-forms.html +lang: ru +--- + +[Web-формы](fa_tech-forms-web.html) [аудита](fa_audit-web.html) были разработаны для отображения объектов, используемых [ICSSoft.STORMNET.Business.Audit.Audit](efs_i-audit.html). Формы расположены в сборке "ICSSoft.STORMNET.Web.AjaxControls.dll". + +Существуют также [win-формы аудита](efs_audit-win-forms.html). + +### Записеориентированные формы аудита + +Записеориентированные формы аудита отображают записи аудита примерно в том же виде, в каком они есть в БД. + +**Списковая форма** позволяет просматривать как аудит по всей системе в целом, так и по конкретному объекту. +Чтобы просматривать данные по всей системе, достаточно просто подключить форму AuditEntityL к проекту (~/Forms/Audit/AuditEntityL.aspx). +Для просмотра данных по конкретному объекту необходимо передать форме дополнительно параметр AuPK, где указан [первичный ключ объект](fo_primary-keys-objects.html), чей аудит необходимо отобразить. + +Например, адрес может быть следующим: . + +**[Форма редактирования](fa_editform.html)** позволяет просмотреть детальную информацию по конкретной записи аудита. На данной форме присутствует таблица, где представлена информация об изменении полей объекта при проведении аудируемой операции. +Отдельной строкой идёт изменение [первичного ключа объекта](fo_primary-keys-objects.html) (такая строка формируется при изменении детейла или мастера). Доступно два режима отображения этих строчек: они совсем не отображаются или они скрываются в древовидную структуру (второй вариант был реализован в [старой версии аудита](efs_audit.html)). По умолчанию реализуется первый вариант, но это можно изменить следующей инициализацией: + +```csharp +UnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. +AIAuditService audittservice = mainUnityContainer.Resolve(); +audittservice.ShowPrimaryKey = true; +``` + +## Объектноориентированные формы аудита + +Объектноориентированные формы аудита ориентированы на отображение информации. + +**Списковая форма** AuditEntityByObjectsL (~/Forms/Audit/AuditEntityByObjectsL.aspx) позволяет просматривать сведения по объектам, над которыми производились аудируемые действия. + +Форма содержит [следующие поля](fa_audit-web.html): + +* Редактирование - дата последнего изменения объекта (создание, изменение или удаление). +* Редактор - имя пользователя, который последний изменял объект. +* Тип объекта - тип аудируемого объекта. +* Идентификатор - идентификатор аудируемого объекта (обычно [первичный ключ](fo_primary-keys-objects.html)). +* Создание - дата создания объекта. +* Создатель - имя пользователя, который создал объект. + +Список по умолчанию отсортирован по дате "Редактирование" (сверху новые). + +**Форма редактирования** AuditEntityByObjectsE позволяет просмотреть детальную информацию по конкретному аудируемому объекту. + +Форма содержит [следующие поля](fa_audit-web.html): + +* Идентификатор - идентификатор аудируемого объекта (обычно [первичный ключ](fo_primary-keys-objects.html)). +* Тип объекта - тип аудируемого объекта. +* Создание - дата создания объекта. +* Создатель - имя пользователя, который создал объект. +* Редактирование - дата последнего изменения объекта (создание, изменение или удаление). +* Редактор - имя пользователя, который последний изменял объект. +* Список полей аудита: + * Время операции - время, когда поле объекта было изменено. + * Тип операции - тип операции, которой было изменено поле. + * Имя - имя пользователя, который совершил аудируемую операцию. + * Логин - логин пользователя, который совершил аудируемую операцию. + * Имя поля - отображаемое имя поля. + * Старое значение - старое значение поля. + * Новое значение - новое значение поля. + * Источник - источник аудируемой операции. + * Результат - итог выполнения операции (удалось ли зафиксировать операцию, был ли провал и др.). + +Список полей аудита отсортирован по времени операции (сверху новые). + +Чтобы отключить отображение записей, содержащих [первичные ключи](fo_primary-keys-objects.html) [мастеров](fd_master-association.html) и [детейлов](fo_detail-associations-properties.html), можно выполнить следующую настройку: + +```csharp +UnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. +AIAuditService audittservice = mainUnityContainer.Resolve(); +audittservice.ShowPrimaryKey = false; +``` + +Если audittservice.ShowPrimaryKey имеет значение true, то список изменений полей отображается [в виде иерархии](fa_wolv-hierarhy.html) аналогично тому, как это сделано в записеориентированных формах аудита. + +> При использовании веб-форм аудита необходимо в файле WebControlProvider.xml добавить следующую информацию: + +```csharp + + + +``` diff --git a/pages/products/flexberry-aspnet/subsystems/security/fa_membership-provider.ru.md b/pages/products/flexberry-aspnet/subsystems/security/fa_membership-provider.ru.md index 82f720c88..83b9aad86 100644 --- a/pages/products/flexberry-aspnet/subsystems/security/fa_membership-provider.ru.md +++ b/pages/products/flexberry-aspnet/subsystems/security/fa_membership-provider.ru.md @@ -1,89 +1,89 @@ ---- -title: CaseberryMembershipProvider -sidebar: flexberry-aspnet_sidebar -keywords: Flexberry ASP-NET, Flexberry Security -toc: true -permalink: ru/fa_membership-provider.html -lang: ru ---- - -## Проверка полномочий для веб-приложений - -Для веб-приложений разработан специальный `MembershipProvider`, позволяющий проверять [полномочия](efs_right-manager-module.html) по БД полномочий без наличия AzManBridgeService. - -## Подключение - -Подключение выглядит следующим образом: - -``` xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -``` - -`CaseberryMembershipProvider ` располагается в сборке `CheckingLibrary.dll` -Чтобы полномочия проверялись, узлу требуется наличие следующих сборок: - -* Security(Objects) -* Security(BusinessServers) -* Repository -* Microsoft.Practices.Unity -* LogService -* log4net -* IIS.Аудит(Objects) -* IIS.Аудит(BusinessServers) -* AppSettingsService -* CheckingLibrary -* ExternalLangDef -* ICSSoft.STORMNET.AzManBridge -* ICSSoft.STORMNET.Business -* ICSSoft.STORMNET.Business.MSSQLDataService -* ICSSoft.STORMNET.Business.OracleDataService -* ICSSoft.STORMNET.Collections -* ICSSoft.STORMNET.DataObject -* ICSSoft.STORMNET.FunctionalLanguage -* ICSSoft.STORMNET.RightManager -* ICSSoft.STORMNET.Tools -* ICSSoft.STORMNET.UserDataTypes -* ICSSoft.STORMNET.Web.Tools - -### Особенности задания строки подключения - -Работа со строкой подключения к БД полномочий происходит следующим образом: - -* Если задана строка подключения с именем `CaseberrySecurity`, то в качестве строки подключения к БД полномочий используется она. -* Если строка подключения `CaseberrySecurity` не задана, то ищется строка соединения с именем вида `CustomizationStrings_applicationName`; то есть если задано, что `applicationName="SLAuthSample"`, то имя строки соединения должно иметь вид `CustomizationStrings_SLAuthSample`. - -## Формы редактирования полномочий в WEB - -В Flexberry ASP.NET есть формы для редактирования полномочий, которые находятся в папке: /forms/Security +--- +title: CaseberryMembershipProvider +sidebar: flexberry-aspnet_sidebar +keywords: Flexberry ASP-NET, Flexberry Security +toc: true +permalink: ru/fa_membership-provider.html +lang: ru +--- + +## Проверка полномочий для веб-приложений + +Для веб-приложений разработан специальный `MembershipProvider`, позволяющий проверять [полномочия](efs_right-manager-module.html) по БД полномочий без наличия AzManBridgeService. + +## Подключение + +Подключение выглядит следующим образом: + +``` xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +``` + +`CaseberryMembershipProvider` располагается в сборке `CheckingLibrary.dll` +Чтобы полномочия проверялись, узлу требуется наличие следующих сборок: + +* Security(Objects) +* Security(BusinessServers) +* Repository +* Microsoft.Practices.Unity +* LogService +* log4net +* IIS.Аудит(Objects) +* IIS.Аудит(BusinessServers) +* AppSettingsService +* CheckingLibrary +* ICSSoft.STORMNET.Business.ExternalLangDef +* ICSSoft.STORMNET.AzManBridge +* ICSSoft.STORMNET.Business +* ICSSoft.STORMNET.Business.MSSQLDataService +* ICSSoft.STORMNET.Business.OracleDataService +* ICSSoft.STORMNET.Collections +* ICSSoft.STORMNET.DataObject +* ICSSoft.STORMNET.FunctionalLanguage +* ICSSoft.STORMNET.RightManager +* ICSSoft.STORMNET.Tools +* ICSSoft.STORMNET.UserDataTypes +* ICSSoft.STORMNET.Web.Tools + +### Особенности задания строки подключения + +Работа со строкой подключения к БД полномочий происходит следующим образом: + +* Если задана строка подключения с именем `CaseberrySecurity`, то в качестве строки подключения к БД полномочий используется она. +* Если строка подключения `CaseberrySecurity` не задана, то ищется строка соединения с именем вида `CustomizationStrings_applicationName`; то есть если задано, что `applicationName="SLAuthSample"`, то имя строки соединения должно иметь вид `CustomizationStrings_SLAuthSample`. + +## Формы редактирования полномочий в WEB + +В Flexberry ASP.NET есть формы для редактирования полномочий, которые находятся в папке: /forms/Security diff --git a/pages/products/flexberry-gis/services/gis-odata-service/gos_gis-odata-service.ru.md b/pages/products/flexberry-gis/services/gis-odata-service/gos_gis-odata-service.ru.md index 8b0ce3694..1b6850961 100644 --- a/pages/products/flexberry-gis/services/gis-odata-service/gos_gis-odata-service.ru.md +++ b/pages/products/flexberry-gis/services/gis-odata-service/gos_gis-odata-service.ru.md @@ -10,13 +10,19 @@ lang: ru ### Особенности настройки OData-сервиса для ГИС-приложений -##### Перед использованием необходимо скачать проекты с github: +##### Перед использованием необходимо скачать проекты с github + [https://github.com/Flexberry/NewPlatform.Flexberry.ORM.GisPostgresDataService](https://github.com/Flexberry/NewPlatform.Flexberry.ORM.GisPostgresDataService) и [https://github.com/Flexberry/NewPlatform.Flexberry.ORM.GisMSSQLDataService](https://github.com/Flexberry/NewPlatform.Flexberry.ORM.GisMSSQLDataService) или загрузить сборки с nuget.org [NewPlatform.Flexberry.ORM.GisPostgresDataService](https://www.nuget.org/packages/NewPlatform.Flexberry.ORM.GisPostgresDataService) и [NewPlatform.Flexberry.ORM.GisMSSQLDataService](https://www.nuget.org/packages/NewPlatform.Flexberry.ORM.GisMSSQLDataService). -##### После успешной компиляции подключить созданные сборки к проекту. Требуется также версия ODataService не ниже 2.0.1-alpha01. Её можно загрузить с nuget.org [NewPlatform.Flexberry.ORM.ODataService](https://www.nuget.org/packages/NewPlatform.Flexberry.ORM.ODataService/2.0.1-alpha01). +##### После успешной компиляции подключить созданные сборки к проекту. + +Требуется также версия ODataService не ниже 2.0.1-alpha01. Её можно загрузить с nuget.org [NewPlatform.Flexberry.ORM.ODataService](https://www.nuget.org/packages/NewPlatform.Flexberry.ORM.ODataService/2.0.1-alpha01). + +##### Изменить файл конфига + +Необходимо изменить файл `Web.config`, отредактировав соответствующую строку таким образом для MSSQL сервер -##### Необходимо изменить файл `Web.config`, отредактировав соответствующую строку таким образом для MSSQL сервер: ```xml ... @@ -25,7 +31,10 @@ lang: ru ... ``` + или для PostgreSQL сервер: + + ```xml ... @@ -34,23 +43,33 @@ lang: ru ... ``` + ### Типы данных + ##### MSSQL сервер + Поле в таблице для MSSQL сервера должна иметь тип `Geography` + ##### PostgreSQL сервер + Поле в таблице для PostgreSQL сервера должна иметь тип `Geography` + ##### .Net + Тип свойства в классе наследуемом от `DataObject` должен быть `Microsoft.Spatial.Geography` ### Использование + ##### В запросе к ODataService + Фильтрация объектов данных в опции запроса $filter возможна с использованием пользовательской функции `geo.intersects(geography1=geo1, geography2=geo2)` в OData, где "geo1" и "geo2" могут быть как полями объектов данных типа Edm.Geography, так и географически привязанными геометриями заданными в формате EWKT, например так: `geo.intersects(geography1=boundingBox, geography2=geography'SRID=<Код используемой системы координат>;POLYGON(<Координаты полигона>)')`, где `geography` - метод для преобразования строки с координатами в формате EWKT в тип Edm.Geography. Пример запроса: `http://localhost/odata/КлассСМножествомТиповs?$filter=PropertyInt eq 5 and geo.intersects(geography1=PropertyGeography, geography2=geography'SRID=4326;POINT(3 3)')`. ##### В запросе к LINQProvider -```c# + +```charp Geography geo = "POINT(3 3)".CreateGeography(); ViewAttribute gisView = new ViewAttribute("gisView", new string[] { "Name as \'Наименование\'", @@ -65,9 +84,13 @@ lang: ru "BoundingBox as \'Граница\'"}); list = ds.Query(new View(gisView, typeof(Map))).Where(d => d.BoundingBox.GeoIntersects(geo)).ToList(); ``` + ##### В запросе с использованием LCS -```c# - var ldef = ExternalLangDef.LanguageDef; + +```charp + IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. + IDataService ds = mainUnityContainer.Resolve(); + ExternalLangDef languageDef = new ExternalLangDef(ds); var lcs = LoadingCustomizationStruct.GetSimpleStruct(typeof (Map), new View(gisView, typeof (Map))); lcs.LimitFunction = ldef.GetFunction(ldef.funcGeoIntersects, new VariableDef(ldef.GeographyType, "BoundingBox"), geo); diff --git a/pages/products/flexberry-orm/additional-features/fo_additional-loading.ru.md b/pages/products/flexberry-orm/additional-features/fo_additional-loading.ru.md index 9994bec73..f43db7c7b 100644 --- a/pages/products/flexberry-orm/additional-features/fo_additional-loading.ru.md +++ b/pages/products/flexberry-orm/additional-features/fo_additional-loading.ru.md @@ -1,169 +1,177 @@ ---- -title: Дочитка объекта данных -sidebar: flexberry-orm_sidebar -keywords: Обхекты данных, Flexberry ORM, дочитка данных, копии данных -summary: Описание способов дочитки данных -toc: true -permalink: ru/fo_additional-loading.html -lang: ru ---- - -Иногда требуется дочитать ранее не загруженные свойства [объекта данных](fo_data-object.html). - -Пусть объект прочитан по [представлению](fd_view-definition.html) "НечтоE". Возможна ситуация, когда для реализации бизнес-логики, например, для выполнения проверок при сохранении объекта, требуется дополнительное подмножество свойств объекта, т.е. объект должен быть загружен по представлению "НечтоПлюсНовыеСвойстваE". Соответственно требуется Дочитать объект. - -Существует несколько способов дочитки данных. Идеального способа, подходящего во всех случаях не существует. Для правильной дочитки данных следует прочитать руководство полностью и выберать наиболее походящий способ догрузки данных. - -{% include note.html content="Если догружаемый объект только создан и ещё не сохранялся в базу ([статус](fo_object-status.html) `Created`), то само понятие `догрузка` к нему не применимо, так как он ни разу не загружался и не существует в базе данных." %} - -## Особенности дочитки данных - -* В зависимости от потребностей задачи должен быть выбран способ работы с [копией объекта данных](fo_data-object-copy.html). Если после дочитки будет выполняться сохранение объекта в БД, значения свойств в [копии](fo_data-object-copy.html) должны быть установлены таким образом, чтобы обеспечить сохранение для всех требуемых свойств. -* Если в объекте данных перед дочиткой были свойства с измененными значениями, для дочитки надо выбрать [представление](fd_view-definition.html) таким образом, чтобы не потерять эти новые значения. - -## Подходы к дочитке данных - -Существует два подхода к реализации дочитки: - -* Логика дочитки полностью реализуется прикладным программистом с помощью использования перегрузки метода `LoadObject`. -В этом случае всю последовательность действий по определению догружаемых свойств и способ работы с [копией данных](fo_data-object-copy.html) выбирает сам программист. Это позволяет наиболее тонко учесть особенности дальнейшего использования объекта в прикладной ситуации. -* Догрузка выполняется с помощью метода `SecondLoadObject` класса `SQLDataService`.В данный метод уже `зашита` стандартная, наиболее часто требуемая, логика работы с копией данных, Flexberry Platform избавляет программиста от необходимости собственной реализации. - -### Реализация дочитки данных в коде - -Когда требуется догрузить данные, а не вычитать объект заново по указанному представлению, следует использовать [перегрузку] метода `LoadObject`(fo_data-service.html) с четырьмя параметрами. Третий из них - `ClearDataObject` - надо устанавливать в `False`. - -``` csharp -/// -/// Загрузка одного объекта данных -/// -/// представление -/// бъект данных, который требуется загрузить -/// очищать ли объект -/// проверять ли существование объекта в хранилище -virtual public void LoadObject( - ICSSoft.STORMNET.View dataObjectView, - ICSSoft.STORMNET.DataObject dobj, bool ClearDataObject, bool CheckExistingObject, DataObjectCache DataObjectCache) -``` - -Если указать `CheckExistingObject = true`, при отсутствии объекта в базе будет выдано исключение типа `CantFindDataObjectException`. - -{% include important.html content="При дочитке происходит переинициализация копии данных объекта. Это значит, что изменения, внесённые в объект с момент загрузки объекта данных до момента дочитки объекта данных, не будут сохранены, т.к. при сохранении идёт сравнение значений полей с полями в [копии данных](fo_data-object-copy.html)."%} - -При этом надо временно отключать переинициализацию копии данных: - -``` csharp -dobj.DisableInitDataCopy(); // запрещаем инициализацию копии данных -ICSSoft.STORMNET.Business.DataServiceProvider.DataService.LoadObject(view, dobj, false, false); // дочитка объекта данных -dobj.EnableInitDataCopy();// возвращаем инициализацию копии данных -dobj.GetStatus();//Для того чтобы статус объекта был вычислен по изменённым свойствам относительно копии данных. -``` - -Важно понимать что после дочитки [статус объекта данных](fo_object-status.html) будет установлен в `UnAltered`, поэтому, если планируется дальнейшее обновление объекта в БД, то не забудьте вызвать `dobj.GetStatus()`, что приведёт к перевычислению статуса по изменённым свойствам относительно [копии данных](fo_data-object-copy.html). - -Данный вариант применим только к случаю, когда догружаемый объект используется только для чтения и не будет в дальнейшем сохраняться в базу. Приведённый код приведёт к тому, что в объекте поля, указанные в [представлении](fd_view-definition.html) дочитки, заполнятся, а в копии объекта данных останутся без изменений. Это, в свою очередь, приведёт к тому, что догруженные поля будут считаться изменёнными (так как расходятся с копией данных), и будут обновляться в базе данных. Поэтому если дочитываемый объект данных будет в дальнейшем сохраняться в базу, то необходимо привести в соответствие [копию данных](fo_data-object-copy.html): - -``` csharp -dobj.DisableInitDataCopy(); // запрещаем инициализацию копии данных -ICSSoft.STORMNET.Business.DataServiceProvider.DataService.LoadObject(view, dobj, false, false); // дочитка объекта данных - -// вручную обновляем внутреннюю копию данных -ТипОбъекта внутренКопия = dobj.GetDataCopy(); -внутренКопия.Поле1 = dobj.Поле1; -внутренКопия.Поле2 = dobj.Поле2; -//... - -внутренКопия.ПолеN = dobj.ПолеN; - -dobj.EnableInitDataCopy();// возвращаем инициализацию копии данных -``` - -Альтернативным вариантом догрузки данных является создания отдельного экземпляра того же типа с таким же [первичным ключом](fo_primary-keys-objects.html) и вычитка по необходимому [представлению](fd_view-definition.html). При этом [представление](fd_view-definition.html) может быть полное или содержать только те атрибуты, которые будут использоваться в дальнейшем: - -``` csharp - // Вручную обновляем внутреннюю копию данных - ТипОбъекта dobj_forLoading = new ТипОбъекта(); - dobj_forLoading.SetExistingPrimaryKey(dobj.__PrimaryKey); - // view - требуемое представление. Его состав зависит от задачи. - ICSSoft.STORMNET.Business.DataServiceProvider.DataService.LoadObject(view, dobj_forLoading); -``` - -{% include note.html content="Если при вызове метода `LoadObject` явно не указать [представление](fd_view-definition.html), то будут вычитываться все собственные поля объекта и ссылки на мастера без собственных полей мастеров. При этом детейлы объекта вычитываться **не будут**." %} - -Чтобы дочитать объект таким образом, необходимо использовать перегрузку метода `LoadObject` без параметра типа `View`. К примеру, подойдет самая простая перегрузка: - -```csharp -ICSSoft.STORMNET.Business.DataServiceProvider.DataService.LoadObject(dobj_forLoading); -``` - -В этом случае объект `dobj_forLoading` также не предназначен для сохранения в базу данных. При этом необходимо понимать, что если объект dobj имеет изменённые свойства (статус `Altered`), то в `dobj_forLoading` они не попадут, так как ещё не сохранены в базу данных. На практике логика не должна зависеть от этого фактора, так как перед дочиткой динамически определяется состав свойств, которые требуется догрузить, при этом изменённые свойства (при правильной проверке) не должны учитываться: - -```csharp -View viewДочитки = new View(); -viewДочитки.DefineClassType = this.GetType(); -if (!dobj.CheckLoadedProperty("Эпизод")) - viewДочитки.AddProperty("Эпизод"); -if (!dobj.CheckLoadedProperty("Эпизод.УД")) - viewДочитки.AddProperty("Эпизод.УД"); -if (!dobj.CheckLoadedProperty("Эпизод.УД.РУОВД")) - viewДочитки.AddProperty("Эпизод.УД.РУОВД"); -if (!dobj.CheckLoadedProperty("Эпизод.УД.РУОВД.Наименование")) - viewДочитки.AddProperty("Эпизод.УД.РУОВД.Наименование"); -if (!dobj.CheckLoadedProperty("Эпизод.УД.ГодДокумента")) - viewДочитки.AddProperty("Эпизод.УД.ГодДокумента"); -if (!dobj.CheckLoadedProperty("Эпизод.УД.НомерУД")) - viewДочитки.AddProperty("Эпизод.УД.НомерУД"); -if (!dobj.CheckLoadedProperty("Эпизод.НомерЭпизода")) - viewДочитки.AddProperty("Эпизод.НомерЭпизода"); -if (!dobj.CheckLoadedProperty("ДатаПоступленияВИЦ")) - viewДочитки.AddProperty("ДатаПоступленияВИЦ"); -if (viewДочитки.Properties.Length > 0) -{ - // дочитка объекта -} -``` - -### Реализация дочитки средствами Flexberry ORM - -Перед использованием данного метода догрузки следует ознакомится с тем, как обновляются значения свойств в обновляемом объекте и его копии, и учитывать это при подготовке объекта к дочитке и его дальнейшем использовании. -Метод имеет следующие параметры: - -``` csharp - /// -/// Метод для дочитки объекта данных. Загруженные ранее свойства не затираются, изменённые свойства не затираются. Подменяются поштучно свойства копии данных. -/// -/// представление -/// бъект данных, который требуется загрузить -/// проверять ли существование объекта в хранилище -/// -protected virtual void SecondLoadObject( -View dataObjectView, -DataObject dataObject, bool checkExistingObject, DataObjectCache dataObjectCache) -``` - -### Дочитка собственных свойств - -* Все собственные свойства обновляются только если не были загружены ранее. - -#### Копия данных - -* Если свойство не было загружено, но было изменено, то обновится значение этого свойства в копии данных (т.е. значение в копии синхронизируется с БД). -* Если свойство было вычитано ранее, то значение в его копии данных не меняется. -* Если копия данных не была инициализирована ранее, то она инициализируется в этот раз относительно базы данных по новому представлению. Это означает что **loaded-свойства, которые достались от предыдущей зачитки останутся с неправильными значениями в копии данных, логика по определению изменённых свойств работать не будет, поэтому все свойства, обозначенные в представлении будут обновлены, кроме тех что есть в массиве loaded** -* Если в объекте отключена инициализация копии данных методом `DisableInitDataCopy()`, то копия данных после дочитки не будет инициализирована. По сути это означает что невозможно понять какие свойства были изменены, а какие нет. Массив LoadedProperties будет содержать массив загруженных свойств. - -#### Дочитка мастеров - -* Если мастер не был вычитан ранее, то он будет зачитан со всеми его мастерами -* Если мастер уже был вычитан, то будут обновлены его свойства по общему принципу -* **Если мастер был зачитан ранее, но был заменён на другой, то будет зачитан новый объект** -* При дочитке мастер проставляется в LoadedProperties даже если явно не был указан в представлении предка и в БД его нет (изменена [стандартная логика](fo_definition-loaded-properties.html)). Мастер не будет указан в LoadedProperties только если LoadingState объекта: `LoadingState.NotLoaded` - -##### Копия данных - -* По стандартной логике копия данных мастерового объекта инициализируется только первичным ключом. - -#### Дочитка детейлов - -* Если детейл не участвовал в loadedProperties, то он зачитывается отдельным массивом и присваивается -* Если детейл был загружен, то производится поэлементное слияние. Объекты, которые не были найдены в коллекции, но были загружены из БД будут добавлены \ No newline at end of file +--- +title: Дочитка объекта данных +sidebar: flexberry-orm_sidebar +keywords: Обхекты данных, Flexberry ORM, дочитка данных, копии данных +summary: Описание способов дочитки данных +toc: true +permalink: ru/fo_additional-loading.html +lang: ru +--- + +Иногда требуется дочитать ранее не загруженные свойства [объекта данных](fo_data-object.html). + +Пусть объект прочитан по [представлению](fd_view-definition.html) "НечтоE". Возможна ситуация, когда для реализации бизнес-логики, например, для выполнения проверок при сохранении объекта, требуется дополнительное подмножество свойств объекта, т.е. объект должен быть загружен по представлению "НечтоПлюсНовыеСвойстваE". Соответственно требуется Дочитать объект. + +Существует несколько способов дочитки данных. Идеального способа, подходящего во всех случаях не существует. Для правильной дочитки данных следует прочитать руководство полностью и выберать наиболее походящий способ догрузки данных. + +{% include note.html content="Если догружаемый объект только создан и ещё не сохранялся в базу ([статус](fo_object-status.html) `Created`), то само понятие `догрузка` к нему не применимо, так как он ни разу не загружался и не существует в базе данных." %} + +## Особенности дочитки данных + +* В зависимости от потребностей задачи должен быть выбран способ работы с [копией объекта данных](fo_data-object-copy.html). Если после дочитки будет выполняться сохранение объекта в БД, значения свойств в [копии](fo_data-object-copy.html) должны быть установлены таким образом, чтобы обеспечить сохранение для всех требуемых свойств. +* Если в объекте данных перед дочиткой были свойства с измененными значениями, для дочитки надо выбрать [представление](fd_view-definition.html) таким образом, чтобы не потерять эти новые значения. + +## Подходы к дочитке данных + +Существует два подхода к реализации дочитки: + +* Логика дочитки полностью реализуется прикладным программистом с помощью использования перегрузки метода `LoadObject`. +В этом случае всю последовательность действий по определению догружаемых свойств и способ работы с [копией данных](fo_data-object-copy.html) выбирает сам программист. Это позволяет наиболее тонко учесть особенности дальнейшего использования объекта в прикладной ситуации. +* Догрузка выполняется с помощью метода `SecondLoadObject` класса `SQLDataService`.В данный метод уже `зашита` стандартная, наиболее часто требуемая, логика работы с копией данных, Flexberry Platform избавляет программиста от необходимости собственной реализации. + +### Реализация дочитки данных в коде + +Когда требуется догрузить данные, а не вычитать объект заново по указанному представлению, следует использовать [перегрузку] метода `LoadObject`(fo_data-service.html) с четырьмя параметрами. Третий из них - `ClearDataObject` - надо устанавливать в `False`. + +``` csharp +/// +/// Загрузка одного объекта данных +/// +/// представление +/// бъект данных, который требуется загрузить +/// очищать ли объект +/// проверять ли существование объекта в хранилище +virtual public void LoadObject( + ICSSoft.STORMNET.View dataObjectView, + ICSSoft.STORMNET.DataObject dobj, bool ClearDataObject, bool CheckExistingObject, DataObjectCache DataObjectCache) +``` + +Если указать `CheckExistingObject = true`, при отсутствии объекта в базе будет выдано исключение типа `CantFindDataObjectException`. + +{% include important.html content="При дочитке происходит переинициализация копии данных объекта. Это значит, что изменения, внесённые в объект с момент загрузки объекта данных до момента дочитки объекта данных, не будут сохранены, т.к. при сохранении идёт сравнение значений полей с полями в [копии данных](fo_data-object-copy.html)."%} + +При этом надо временно отключать переинициализацию копии данных: + +``` csharp +dobj.DisableInitDataCopy(); // запрещаем инициализацию копии данных +IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. +IDataService ds = mainUnityContainer .Resolve(); +ICSSoft.STORMNET.Business.ds.LoadObject(view, dobj, false, false); // дочитка объекта данных +dobj.EnableInitDataCopy();// возвращаем инициализацию копии данных +dobj.GetStatus();//Для того чтобы статус объекта был вычислен по изменённым свойствам относительно копии данных. +``` + +Важно понимать что после дочитки [статус объекта данных](fo_object-status.html) будет установлен в `UnAltered`, поэтому, если планируется дальнейшее обновление объекта в БД, то не забудьте вызвать `dobj.GetStatus()`, что приведёт к перевычислению статуса по изменённым свойствам относительно [копии данных](fo_data-object-copy.html). + +Данный вариант применим только к случаю, когда догружаемый объект используется только для чтения и не будет в дальнейшем сохраняться в базу. Приведённый код приведёт к тому, что в объекте поля, указанные в [представлении](fd_view-definition.html) дочитки, заполнятся, а в копии объекта данных останутся без изменений. Это, в свою очередь, приведёт к тому, что догруженные поля будут считаться изменёнными (так как расходятся с копией данных), и будут обновляться в базе данных. Поэтому если дочитываемый объект данных будет в дальнейшем сохраняться в базу, то необходимо привести в соответствие [копию данных](fo_data-object-copy.html): + +``` csharp +dobj.DisableInitDataCopy(); // запрещаем инициализацию копии данных +IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. +IDataService ds = mainUnityContainer .Resolve(); +ICSSoft.STORMNET.Business.ds.LoadObject(view, dobj, false, false); // дочитка объекта данных + +// вручную обновляем внутреннюю копию данных +ТипОбъекта внутренКопия = dobj.GetDataCopy(); +внутренКопия.Поле1 = dobj.Поле1; +внутренКопия.Поле2 = dobj.Поле2; +//... + +внутренКопия.ПолеN = dobj.ПолеN; + +dobj.EnableInitDataCopy();// возвращаем инициализацию копии данных +``` + +Альтернативным вариантом догрузки данных является создания отдельного экземпляра того же типа с таким же [первичным ключом](fo_primary-keys-objects.html) и вычитка по необходимому [представлению](fd_view-definition.html). При этом [представление](fd_view-definition.html) может быть полное или содержать только те атрибуты, которые будут использоваться в дальнейшем: + +``` csharp +// Вручную обновляем внутреннюю копию данных +ТипОбъекта dobj_forLoading = new ТипОбъекта(); +dobj_forLoading.SetExistingPrimaryKey(dobj.__PrimaryKey); +// view - требуемое представление. Его состав зависит от задачи. +IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. +IDataService ds = mainUnityContainer .Resolve(); +ICSSoft.STORMNET.Business.ds.LoadObject(view, dobj_forLoading); +``` + +{% include note.html content="Если при вызове метода `LoadObject` явно не указать [представление](fd_view-definition.html), то будут вычитываться все собственные поля объекта и ссылки на мастера без собственных полей мастеров. При этом детейлы объекта вычитываться **не будут**." %} + +Чтобы дочитать объект таким образом, необходимо использовать перегрузку метода `LoadObject` без параметра типа `View`. К примеру, подойдет самая простая перегрузка: + +```csharp +IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. +IDataService ds = mainUnityContainer .Resolve(); +ICSSoft.STORMNET.Business.ds.LoadObject(dobj_forLoading); +``` + +В этом случае объект `dobj_forLoading` также не предназначен для сохранения в базу данных. При этом необходимо понимать, что если объект dobj имеет изменённые свойства (статус `Altered`), то в `dobj_forLoading` они не попадут, так как ещё не сохранены в базу данных. На практике логика не должна зависеть от этого фактора, так как перед дочиткой динамически определяется состав свойств, которые требуется догрузить, при этом изменённые свойства (при правильной проверке) не должны учитываться: + +```csharp +View viewДочитки = new View(); +viewДочитки.DefineClassType = this.GetType(); +if (!dobj.CheckLoadedProperty("Эпизод")) + viewДочитки.AddProperty("Эпизод"); +if (!dobj.CheckLoadedProperty("Эпизод.УД")) + viewДочитки.AddProperty("Эпизод.УД"); +if (!dobj.CheckLoadedProperty("Эпизод.УД.РУОВД")) + viewДочитки.AddProperty("Эпизод.УД.РУОВД"); +if (!dobj.CheckLoadedProperty("Эпизод.УД.РУОВД.Наименование")) + viewДочитки.AddProperty("Эпизод.УД.РУОВД.Наименование"); +if (!dobj.CheckLoadedProperty("Эпизод.УД.ГодДокумента")) + viewДочитки.AddProperty("Эпизод.УД.ГодДокумента"); +if (!dobj.CheckLoadedProperty("Эпизод.УД.НомерУД")) + viewДочитки.AddProperty("Эпизод.УД.НомерУД"); +if (!dobj.CheckLoadedProperty("Эпизод.НомерЭпизода")) + viewДочитки.AddProperty("Эпизод.НомерЭпизода"); +if (!dobj.CheckLoadedProperty("ДатаПоступленияВИЦ")) + viewДочитки.AddProperty("ДатаПоступленияВИЦ"); +if (viewДочитки.Properties.Length > 0) +{ + // дочитка объекта +} +``` + +### Реализация дочитки средствами Flexberry ORM + +Перед использованием данного метода догрузки следует ознакомится с тем, как обновляются значения свойств в обновляемом объекте и его копии, и учитывать это при подготовке объекта к дочитке и его дальнейшем использовании. +Метод имеет следующие параметры: + +``` csharp + /// +/// Метод для дочитки объекта данных. Загруженные ранее свойства не затираются, изменённые свойства не затираются. Подменяются поштучно свойства копии данных. +/// +/// представление +/// бъект данных, который требуется загрузить +/// проверять ли существование объекта в хранилище +/// +protected virtual void SecondLoadObject( +View dataObjectView, +DataObject dataObject, bool checkExistingObject, DataObjectCache dataObjectCache) +``` + +### Дочитка собственных свойств + +* Все собственные свойства обновляются только если не были загружены ранее. + +#### Копия данных + +* Если свойство не было загружено, но было изменено, то обновится значение этого свойства в копии данных (т.е. значение в копии синхронизируется с БД). +* Если свойство было вычитано ранее, то значение в его копии данных не меняется. +* Если копия данных не была инициализирована ранее, то она инициализируется в этот раз относительно базы данных по новому представлению. Это означает что **loaded-свойства, которые достались от предыдущей зачитки останутся с неправильными значениями в копии данных, логика по определению изменённых свойств работать не будет, поэтому все свойства, обозначенные в представлении будут обновлены, кроме тех что есть в массиве loaded** +* Если в объекте отключена инициализация копии данных методом `DisableInitDataCopy()`, то копия данных после дочитки не будет инициализирована. По сути это означает что невозможно понять какие свойства были изменены, а какие нет. Массив LoadedProperties будет содержать массив загруженных свойств. + +#### Дочитка мастеров + +* Если мастер не был вычитан ранее, то он будет зачитан со всеми его мастерами +* Если мастер уже был вычитан, то будут обновлены его свойства по общему принципу +* **Если мастер был зачитан ранее, но был заменён на другой, то будет зачитан новый объект** +* При дочитке мастер проставляется в LoadedProperties даже если явно не был указан в представлении предка и в БД его нет (изменена [стандартная логика](fo_definition-loaded-properties.html)). Мастер не будет указан в LoadedProperties только если LoadingState объекта: `LoadingState.NotLoaded` + +##### Копия данных + +* По стандартной логике копия данных мастерового объекта инициализируется только первичным ключом. + +#### Дочитка детейлов + +* Если детейл не участвовал в loadedProperties, то он зачитывается отдельным массивом и присваивается +* Если детейл был загружен, то производится поэлементное слияние. Объекты, которые не были найдены в коллекции, но были загружены из БД будут добавлены diff --git a/pages/products/flexberry-orm/additional-features/fo_asynchronous_requests_in_orm.ru.md b/pages/products/flexberry-orm/additional-features/fo_asynchronous_requests_in_orm.ru.md index 2d206c535..fea53af3b 100644 --- a/pages/products/flexberry-orm/additional-features/fo_asynchronous_requests_in_orm.ru.md +++ b/pages/products/flexberry-orm/additional-features/fo_asynchronous_requests_in_orm.ru.md @@ -20,7 +20,7 @@ lang: ru | UpdateObjectAsync | Сохранение объекта данных | `DataObject` - объект, который нужно сохранить. | | UpdateObjectsAsync | Сохранение нескольких объектов данных | `DataObject[]`` - массив объектов, который нужно сохранить. | -__Дополнительные параметры__ +#### Дополнительные параметры - `clearDataObject` (для загрузки) - очищать объект (`DataObject.Clear`) перед вычиткой (по умолчанию `true`); - `alwaysThrowException` (для обновления) - сразу же останавливать метод при возникновении ошибки (если `false` - будет произведена попытка выполнить часть запросов несмотря на ошибки; по умолчанию `false`); @@ -28,7 +28,7 @@ __Дополнительные параметры__ ### Особенности работы -Асинхронные методы изменяют переданные в метод экземпляры объектов, т.е. работают с объектами как с mutable object. Это требует особого внимания при работе с объектами до завершения операций загрузки/обновления (состояние объектов может измениться). Во избежание ошибок, следует использовать `await` или `Task.Wait` до того, как будет продолжена работа с объектом (либо клонировать исходный объект). +Асинхронные методы *изменяют переданные в метод экземпляры объектов*, т.е. работают с объектами как с mutable object. Это требует особого внимания при работе с объектами до завершения операций загрузки/обновления (состояние объектов может измениться). Во избежание ошибок, следует использовать `await` или `Task.Wait` до того, как будет продолжена работа с объектом (либо клонировать исходный объект). ### Примеры использования @@ -36,7 +36,8 @@ __Дополнительные параметры__ ```csharp using ICSSoft.STORMNET.Business; -var DS = DataServiceProvider.DataService as SQLDataService; +IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. +IDataService ds = mainUnityContainer.Resolve(); // объект для загрузки var userToLoad = new Пользователь(); @@ -45,8 +46,8 @@ userToLoad.SetExistObjectPrimaryKey(user1.__PrimaryKey); //указываем к // поля для загрузки: var view = new View { DefineClassType = typeof(Пользователь) }; view.AddProperties( - Information.ExtractPropertyPath<Пользователь>(x => x.ФИО), - Information.ExtractPropertyPath<Пользователь>(x => x.ДатаРегистрации)); + Information.ExtractPropertyPath<Пользователь>(x => x.ФИО), + Information.ExtractPropertyPath<Пользователь>(x => x.ДатаРегистрации)); await DS.LoadObjectAsync(userToLoad, view); //обновляется объект userToLoad (догружаются указанные поля) ``` @@ -69,18 +70,20 @@ var loadedObjects = (await ds.LoadObjectsAsync(lcsDateAfter2000)).Cast<Поль 2. Вызывать асинхронные методы датасервиса из асинхронного кода (с модификатором `async`): На текущий момент можно добавить модификатор `async`: + - для контроллеров WebApi в `ODataBackend`; - для OData функций; - для метода `Main` в консольных программах/сервисах (код сервиса рекомендуется также сделать асинхронным); - для библиотек классов; Нельзя добавить модификатор `async`: + - для бизнес-серверов (OnUpdate/OnDelete/OnInsert); - для методов класса `Startup.cs`; если вам все-же нужны асинхронные операции в `Startup.cs`, см. статью ["Асинхронный код в Startup ASP.NET Core: 4 способа обхода GetAwaiter().GetResult()"](https://habr.com/ru/company/dododev/blog/496300/) (решение №2 и №3). -__Преимущества перехода__ +#### Преимущества перехода -1. Пропускная способность (throughput) асинхронного кода при нагрузке гораздо выше. Это особенно заметно, когда количество потоков, выполняемых одновременно, превышает thread pool (["Measuring performance for async vs sync code in ASP.NET Core"](https://stackoverflow.com/a/62919974)): +1.Пропускная способность (throughput) асинхронного кода при нагрузке гораздо выше. Это особенно заметно, когда количество потоков, выполняемых одновременно, превышает thread pool (["Measuring performance for async vs sync code in ASP.NET Core"](https://stackoverflow.com/a/62919974)): ```csharp 5000 sync calls 5546ms 35 threads @@ -89,9 +92,9 @@ __Преимущества перехода__ Прирост пропуской способности достигается за счёт освобождения потока при вызове `await`. Синхронный код (без async/await) под нагрузкой требует больше потоков (["Async vs Sync Benchmark (.NET)"](https://artemmikulich.medium.com/async-vs-sync-benchmark-net-f1e752a57755)), соответственно его пропускная способность под нагрузкой ниже. -2. Код выполнится быстрее, если задействовать для задачи несколько потоков, работающих одновременно. В этом случае прирост к скорости будет приобретён ценой возросшей нагрузки на одну задачу. Прирост заметен только когда в thread pool есть свободные потоки (при невысокой нагрузке). -3. В UI приложениях (напр. [Windows Forms](fw_landing_page.html)) текущий поток может быть освобождён, и интерфейс не будет блокироваться ("замораживаться"). +2.Код выполнится быстрее, если задействовать для задачи несколько потоков, работающих одновременно. В этом случае прирост к скорости будет приобретён ценой возросшей нагрузки на одну задачу. Прирост заметен только когда в thread pool есть свободные потоки (при невысокой нагрузке). +3.В UI приложениях (напр. [Windows Forms](fw_landing_page.html)) текущий поток может быть освобождён, и интерфейс не будет блокироваться ("замораживаться"). -__Недостатки__ +#### Недостатки -1. Сложность использования в синхронном коде. Асинхронный код можно вызывать через `Task.Run()`, но могут возникнуть проблемы (подробнее об этом в статье ["Avoid using Task.Run for long running work that blocks the thread"](https://github.com/davidfowl/AspNetCoreDiagnosticScenarios/blob/master/AsyncGuidance.md#avoid-using-taskrun-for-long-running-work-that-blocks-the-thread)). \ No newline at end of file +1. Сложность использования в синхронном коде. Асинхронный код можно вызывать через `Task.Run()`, но могут возникнуть проблемы (подробнее об этом в статье ["Avoid using Task.Run for long running work that blocks the thread"](https://github.com/davidfowl/AspNetCoreDiagnosticScenarios/blob/master/AsyncGuidance.md#avoid-using-taskrun-for-long-running-work-that-blocks-the-thread)). diff --git a/pages/products/flexberry-orm/additional-features/fo_custom-naming-db-structures.ru.md b/pages/products/flexberry-orm/additional-features/fo_custom-naming-db-structures.ru.md index ecf5791fd..625887214 100644 --- a/pages/products/flexberry-orm/additional-features/fo_custom-naming-db-structures.ru.md +++ b/pages/products/flexberry-orm/additional-features/fo_custom-naming-db-structures.ru.md @@ -1,50 +1,51 @@ ---- -title: Пример пользовательских наименований для структур в БД -sidebar: flexberry-orm_sidebar -keywords: Public, пример, базы данных, Flexberry Desinger, диаграммы -summary: Задание наименований для базы данных -toc: true -permalink: ru/fo_custom-naming-db-structures.html -lang: ru ---- - -Существует 2 пути для [определения наименования](fo_storing-data-objects.html): - -* во Flexberry Desinger -* в C# коде с помощью атрибутов. - -Если выбран первый путь, то Flexberry Desinger сгенерирует соответствующие имена автоматически. - -Можно [соотнести объекты данных и атрибуты с любым наименованием БД-структуры](fo_storing-data-objects.html): - -* Имя таблицы для класса (атрибут [ClassStorage](fd_data-classes.html) для класса); -* Имя столбца для атрибута (атрибут [PropertyStorage](fo_attributes-class-data.html) для свойства); -* Имя столбца [первичного ключа (Primary key)](fo_primary-keys-objects.html) для идентификатора объекта данных (атрибут [PrimaryKeyStorage](fd_data-classes.html) для класса); -* Имя столбца внешнего ключа (Foreign key) для зависимостей мастера (атрибут [PropertyStorage](fd_master-association.html) для свойства); - -Например, диаграмма `DB structures custom naming`: - -* `CustomDBOwnClass` относится к таблице `CustomDBOwn`; -* `CustomDBOwnClass.CustomOwnAttribute` относится к столбцу `CustomOwn` в таблице `CustomDBOwn`; -* `CustomDBMasterClass` относится к таблице `CustomDBMaster`; -* `CustomDBMasterClass.CustomMasterAttribute` относится к столбцу CustomMaster в таблице `CustomDBOwnCustomDBMaster`; -* Отношение `CustomDBOwnClass` к `CustomDBMasterClass` определяется в столбце `CustomDBMaster` в таблице `CustomDBOwnClass`; -* Идентификаторы обоих классов относятся к столбцу `pkey` в соответствующих таблицах `tables` - -Достаточно создать объекты и сохранить их. - -```csharp -CustomDBOwnClass cdbo = new CustomDBOwnClass(); -CustomDBMasterClass cdbm = new CustomDBMasterClass(); -cdbm.CustomMasterAttribute = new RandomStringGenerator().Generate(200); -cdbo.CustomDBMasterClass = cdbm; -cdbo.CustomOwnAttribute = new RandomStringGenerator().Generate(200); - -IDataService dataService = DataServiceProvider.DataService; -ICSSoft.STORMNET.DataObject[] objstoupd = new ICSSoft.STORMNET.DataObject[] { cdbo, cdbm }; -dataService.UpdateObjects(ref objstoupd); - -Console.WriteLine("OK!"); -``` - -Полный список примеров кода Flexberry ORM находится в статье ["Примеры кода"](fo_code-samples.html). +--- +title: Пример пользовательских наименований для структур в БД +sidebar: flexberry-orm_sidebar +keywords: Public, пример, базы данных, Flexberry Desinger, диаграммы +summary: Задание наименований для базы данных +toc: true +permalink: ru/fo_custom-naming-db-structures.html +lang: ru +--- + +Существует 2 пути для [определения наименования](fo_storing-data-objects.html): + +* во Flexberry Desinger +* в C# коде с помощью атрибутов. + +Если выбран первый путь, то Flexberry Desinger сгенерирует соответствующие имена автоматически. + +Можно [соотнести объекты данных и атрибуты с любым наименованием БД-структуры](fo_storing-data-objects.html): + +* Имя таблицы для класса (атрибут [ClassStorage](fd_data-classes.html) для класса); +* Имя столбца для атрибута (атрибут [PropertyStorage](fo_attributes-class-data.html) для свойства); +* Имя столбца [первичного ключа (Primary key)](fo_primary-keys-objects.html) для идентификатора объекта данных (атрибут [PrimaryKeyStorage](fd_data-classes.html) для класса); +* Имя столбца внешнего ключа (Foreign key) для зависимостей мастера (атрибут [PropertyStorage](fd_master-association.html) для свойства); + +Например, диаграмма `DB structures custom naming`: + +* `CustomDBOwnClass` относится к таблице `CustomDBOwn`; +* `CustomDBOwnClass.CustomOwnAttribute` относится к столбцу `CustomOwn` в таблице `CustomDBOwn`; +* `CustomDBMasterClass` относится к таблице `CustomDBMaster`; +* `CustomDBMasterClass.CustomMasterAttribute` относится к столбцу CustomMaster в таблице `CustomDBOwnCustomDBMaster`; +* Отношение `CustomDBOwnClass` к `CustomDBMasterClass` определяется в столбце `CustomDBMaster` в таблице `CustomDBOwnClass`; +* Идентификаторы обоих классов относятся к столбцу `pkey` в соответствующих таблицах `tables` + +Достаточно создать объекты и сохранить их. + +```csharp +CustomDBOwnClass cdbo = new CustomDBOwnClass(); +CustomDBMasterClass cdbm = new CustomDBMasterClass(); +cdbm.CustomMasterAttribute = new RandomStringGenerator().Generate(200); +cdbo.CustomDBMasterClass = cdbm; +cdbo.CustomOwnAttribute = new RandomStringGenerator().Generate(200); + +IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. +IDataService ds = mainUnityContainer.Resolve(); +ICSSoft.STORMNET.DataObject[] objstoupd = new ICSSoft.STORMNET.DataObject[] { cdbo, cdbm }; +ds.UpdateObjects(ref objstoupd); + +Console.WriteLine("OK!"); +``` + +Полный список примеров кода Flexberry ORM находится в статье ["Примеры кода"](fo_code-samples.html). diff --git a/pages/products/flexberry-orm/additional-features/fo_flexberry-orm-libraries.ru.md b/pages/products/flexberry-orm/additional-features/fo_flexberry-orm-libraries.ru.md index b046730bf..343a1dc0c 100644 --- a/pages/products/flexberry-orm/additional-features/fo_flexberry-orm-libraries.ru.md +++ b/pages/products/flexberry-orm/additional-features/fo_flexberry-orm-libraries.ru.md @@ -1,32 +1,32 @@ ---- -title: Библиотеки Flexberry ORM -sidebar: flexberry-orm_sidebar -keywords: Flexberry ORM, библиотеки, сборки, nuget -summary: Список библиотек Flexberry ORM, доступных через NuGet -toc: true -permalink: ru/fo_flexberry-orm-libraries.html -lang: ru ---- - -Список библиотек, содержащих Runtime-компоненты [Flexberry ORM](fo_flexberry-orm.html): - -* **ChangesToSqlBTMonitor.dll** - библиотека, содержащая классы для работы [сервиса записи SQL-скриптов изменения данных](fo_changes-sql-bt-monitor.html). -* **ExternalLangDef.dll** - библиотека, содержащая [расширение языка ограничений](fo_external-lang-def.html) для [задания ограничений](fo_limit-function.html) на зависимые объекты. -* **ICSSoft.STORMNET.BF.dll** -* **ICSSoft.STORMNET.Business.dll** - библиотека, содержащая базовые классы для организации [отображения структуры реляционных таблиц БД на объектную модель](fo_data-service.html). -* **ICSSoft.STORMNET.Business.DRDataService.dll** - библиотека, содержащая классы для работы [DRDataService](fo_dr-data-service.html). -* **ICSSoft.STORMNET.Business.LINQProvider.dll** - библиотека, содержащая классы для поддержки LINQ в [Flexberry ORM](fo_flexberry-orm.html). -* **ICSSoft.STORMNET.Business.LockService.dll** - библиотека, содержащая классы для работы [сервиса блокировок](fo_lock-service.html). -* **ICSSoft.STORMNET.Business.MSSQLDataService.dll** - библиотека, содержащая классы для [организации отображения структуры реляционных таблиц MS SQL Server (версии 2005 и выше) на объектную модель](fo_data-service.html). -* **ICSSoft.STORMNET.Business.ODBCDataService.dll** - библиотека, содержащая классы для работы [ODBCDataService](fo_odbc-data-service.html). -* **ICSSoft.STORMNET.Business.OracleDataService.dll** - библиотека, содержащая классы для работы [OracleDataService](fo_oracle-data-service.html). -* **ICSSoft.STORMNET.Business.PostgresDataService.dll** - библиотека, содержащая классы для работы [PostgresDataService](fo_postgres-data-service.html). -* **ICSSoft.STORMNET.Collections.dll** - библиотека, содержащая вспомогательные базовые структуры для организации коллекций объектов. -* **ICSSoft.STORMNET.DataObject.dll** - библиотека, содержащая базовые классы для организации [объектной модели](fo_data-object.html), а также основные вспомогательные методы для работы с ними. -* ICSSoft.STORMNET.Drawing.dll -* **ICSSoft.STORMNET.FunctionalLanguage.dll** - библиотека, содержащая основные классы для функционирования [компоненты работы с фильтрами и ограничениями](fo_limitation.html). -* **ICSSoft.STORMNET.Tools.dll** - библиотека, содержащая общие вспомогательные методы. -* **ICSSoft.STORMNET.UserDataTypes.dll** - библиотека, содержащая дополнительно определённые типы данных. -* **NewPlatform.Flexberry.Data.ODataService.dll** - -{% include note.html content="Flexberry ORM доступно для установки в проект через [NuGet package](https://www.nuget.org/packages/NewPlatform.Flexberry.ORM)." %} +--- +title: Библиотеки Flexberry ORM +sidebar: flexberry-orm_sidebar +keywords: Flexberry ORM, библиотеки, сборки, nuget +summary: Список библиотек Flexberry ORM, доступных через NuGet +toc: true +permalink: ru/fo_flexberry-orm-libraries.html +lang: ru +--- + +Список библиотек, содержащих Runtime-компоненты [Flexberry ORM](fo_flexberry-orm.html): + +* **ChangesToSqlBTMonitor.dll** - библиотека, содержащая классы для работы [сервиса записи SQL-скриптов изменения данных](fo_changes-sql-bt-monitor.html). +* **ICSSoft.STORMNET.Business.ExternalLangDef.dll** - библиотека, содержащая [расширение языка ограничений](fo_external-lang-def.html) для [задания ограничений](fo_limit-function.html) на зависимые объекты. +* **ICSSoft.STORMNET.BF.dll** +* **ICSSoft.STORMNET.Business.dll** - библиотека, содержащая базовые классы для организации [отображения структуры реляционных таблиц БД на объектную модель](fo_data-service.html). +* **ICSSoft.STORMNET.Business.DRDataService.dll** - библиотека, содержащая классы для работы [DRDataService](fo_dr-data-service.html). +* **ICSSoft.STORMNET.Business.LINQProvider.dll** - библиотека, содержащая классы для поддержки LINQ в [Flexberry ORM](fo_flexberry-orm.html). +* **ICSSoft.STORMNET.Business.LockService.dll** - библиотека, содержащая классы для работы [сервиса блокировок](fo_lock-service.html). +* **ICSSoft.STORMNET.Business.MSSQLDataService.dll** - библиотека, содержащая классы для [организации отображения структуры реляционных таблиц MS SQL Server (версии 2005 и выше) на объектную модель](fo_data-service.html). +* **ICSSoft.STORMNET.Business.ODBCDataService.dll** - библиотека, содержащая классы для работы [ODBCDataService](fo_odbc-data-service.html). +* **ICSSoft.STORMNET.Business.OracleDataService.dll** - библиотека, содержащая классы для работы [OracleDataService](fo_oracle-data-service.html). +* **ICSSoft.STORMNET.Business.PostgresDataService.dll** - библиотека, содержащая классы для работы [PostgresDataService](fo_postgres-data-service.html). +* **ICSSoft.STORMNET.Collections.dll** - библиотека, содержащая вспомогательные базовые структуры для организации коллекций объектов. +* **ICSSoft.STORMNET.DataObject.dll** - библиотека, содержащая базовые классы для организации [объектной модели](fo_data-object.html), а также основные вспомогательные методы для работы с ними. +* ICSSoft.STORMNET.Drawing.dll +* **ICSSoft.STORMNET.FunctionalLanguage.dll** - библиотека, содержащая основные классы для функционирования [компоненты работы с фильтрами и ограничениями](fo_limitation.html). +* **ICSSoft.STORMNET.Tools.dll** - библиотека, содержащая общие вспомогательные методы. +* **ICSSoft.STORMNET.UserDataTypes.dll** - библиотека, содержащая дополнительно определённые типы данных. +* **NewPlatform.Flexberry.Data.ODataService.dll** + +{% include note.html content="Flexberry ORM доступно для установки в проект через [NuGet package](https://www.nuget.org/packages/NewPlatform.Flexberry.ORM)." %} diff --git a/pages/products/flexberry-orm/authority-audit/efs_AuditWebApiExample.ru.md b/pages/products/flexberry-orm/authority-audit/efs_AuditWebApiExample.ru.md index 795324d8e..3c25eaadc 100644 --- a/pages/products/flexberry-orm/authority-audit/efs_AuditWebApiExample.ru.md +++ b/pages/products/flexberry-orm/authority-audit/efs_AuditWebApiExample.ru.md @@ -1,145 +1,154 @@ ---- -title: Пример использования API подсистемы аудита. Создание и подтверждение собственных записей аудита -sidebar: ember-flexberry-security_sidebar -keywords: Flexberry Audit -toc: true -permalink: ru/efs_audit-web-api-example.html -lang: ru ---- - -## Задача -Вести аудит формирований отчетов - -## Дано -* Метод формирования отчета -* Подсистема аудита - -## Решение -Допустим, что у нас есть некий метод формирования отчета: - -``` -public static Отчет СоздатьОтчетПоКлиенту(Клиент клиент) -{ - var report = new Отчет(); - - // Создаем отчет ... - - return report; -} -``` - -Необходимо модифицировать его, добавив ведение аудита формирований отчетов. - -Для начала необходимо записать в базу факт начала формирования отчета, использовав метод `[AuditWebApi#WriteCustomAuditOperation_2|WriteCustomAuditOperation]`. - -Метод принимает в качестве параметра экземпляр класса `[AuditWebApi#CustomAuditParameters_0|CustomAuditParameters]`. Создадим его: - -``` - -var auditParams = new CustomAuditParameters -{ - CustomAuditOperation = string.Format("Создание отчета по клиенту {0} (ID: {1})", клиент.ФИО, клиент.__PrimaryKey), - ExecutionResult = tExecutionVariant.Unknown, - OperationTime = DateTime.Now, - UseDefaultWriteMode = true -}; -``` - -Обратим внимание, что мы не передаем никакого объекта (свойство `AuditDataObject`), так как у нас фактически ничего не изменяется. - -Так как мы не знаем результата операции формирования отчета, мы выставляем ExecutionResult = tExecutionVariant.Unknown - -Теперь можно записать данные в базу аудита: - -``` - Guid? auditOperationId = AuditService.Current.WriteCustomAuditOperation(auditParams, true); -``` - -Используем самую простую перегрузку метода `WriteCustomAuditOperation`, DataService определится как стандартный для приложения. - -Результатом выполнения операции является ID созданной записи в БД аудита. Запомним его, он пригодится нам позже. - -Далее необходимо каким либо образом определить результат выполняемой операции и обновить результат в базе при помощи метода `[AuditWebApi#RatifyAuditOperation_3|RatifyAuditOperation]`, воспользуемся блоком try-catch-finally: - -``` - -bool correct = true; - -try -{ - // Создаем отчет ... -} -catch(Exception ex) -{ - // Записываем ошибку в лог ... - - // Запоминаем факт возникновения ошибки - correct = false; -} -finally -{ - // Обновим статус операции в базе в соответствии с результатами построения отчета - AuditService.Current.RatifyAuditOperation( - correct ? tExecutionVariant.Executed : tExecutionVariant.Failed, - new List { auditOperationId.Value }, - false); -} -``` - - -## Результат -Теперь при попытке создания отчета в базе данных аудита создастся соответствующая запись. Статус выполнения операции будет зависеть от успешности её выполнения. - -### Измененный метод -``` - - public static Отчет СоздатьОтчетПоКлиенту(Клиент клиент) - { - // Заносим данные о начале операции создании отчета в подсистему аудита - var auditParams = new CustomAuditParameters - { - CustomAuditOperation = string.Format("Создание отчета по клиенту {0} (ID: {1})", клиент.ФИО, клиент.__PrimaryKey), - ExecutionResult = tExecutionVariant.Unknown, - OperationTime = DateTime.Now, - UseDefaultWriteMode = true - }; - - // Записываем операцию аудита в базу и запоминаем ID созданной записи - Guid? auditOperationId = AuditService.Current.WriteCustomAuditOperation(auditParams, true); - - var report = new Отчет(); - bool correct = true; - - try - { - // Создаем отчет ... - } - catch(Exception ex) - { - // Записываем ошибку в лог ... - - // Запоминаем факт возникновения ошибки - correct = false; - } - finally - { - // Обновим статус операции в базе в соответствии с результатами построения отчета - AuditService.Current.RatifyAuditOperation( - correct ? tExecutionVariant.Executed : tExecutionVariant.Failed, - new List { auditOperationId.Value }, - false); - } - - return report; - } -``` - -### Web-интерфейс -После попытки создания двух отчетов, одна из которых прошла успешно, а вторая неудачно: - -Форма просмотра записей аудита (частично): -![Изображение](/images/img/page/AuditWebApiExample/AuditWebApiWolv.PNG) - - -Форма просмотра деталей записи аудита: -![Изображение](/images/img/page/AuditWebApiExample/AuditWebApiE.PNG) +--- +title: Пример использования API подсистемы аудита. Создание и подтверждение собственных записей аудита +sidebar: ember-flexberry-security_sidebar +keywords: Flexberry Audit +toc: true +permalink: ru/efs_audit-web-api-example.html +lang: ru +--- + +## Задача + +Вести аудит формирований отчетов + +## Дано + +* Метод формирования отчета +* Подсистема аудита + +## Решение + +Допустим, что есть некий метод формирования отчета: + +```csharp +public static Отчет СоздатьОтчетПоКлиенту(Клиент клиент) +{ + var report = new Отчет(); + + // Создать отчет ... + + return report; +} +``` + +Необходимо модифицировать его, добавив ведение аудита формирований отчетов. + +В первую очередь, необходимо записать в базу факт начала формирования отчета, использовав метод `[AuditWebApi#WriteCustomAuditOperation_2|WriteCustomAuditOperation]`. + +Метод принимает в качестве параметра экземпляр класса `[AuditWebApi#CustomAuditParameters_0|CustomAuditParameters]`. Создадать его можно следующим образом: + +```csharp +var auditParams = new CustomAuditParameters +{ + CustomAuditOperation = string.Format("Создание отчета по клиенту {0} (ID: {1})", клиент.ФИО, клиент.__PrimaryKey), + ExecutionResult = tExecutionVariant.Unknown, + OperationTime = DateTime.Now, + UseDefaultWriteMode = true +}; +``` + +Объект не передается (свойство `AuditDataObject`), так как фактически ничего не изменяется. + +Исходя из того, что результат операции формирования отчета не известен, ExecutionResult = tExecutionVariant.Unknown + +Теперь можно записать данные в базу аудита: + +```csharp +UnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. +AIAuditService audittservice = mainUnityContainer.Resolve(); +Guid? auditOperationId = audittservice.WriteCustomAuditOperation(auditParams, true); +``` + +Используется самая простая перегрузка метода `WriteCustomAuditOperation`, IDataService определится как стандартный для приложения. + +Результатом выполнения операции является ID созданной записи в БД аудита. Этот результат потребуется позже. + +Далее необходимо каким либо образом определить результат выполняемой операции и обновить результат в базе при помощи метода `[AuditWebApi#RatifyAuditOperation_3|RatifyAuditOperation]`, для этого используется блок try-catch-finally: + +```csharp +bool correct = true; + +try +{ + // Создать отчет ... +} +catch(Exception ex) +{ + // Записать ошибку в лог ... + + // Запоминить факт возникновения ошибки + correct = false; +} +finally +{ + // Обновить статус операции в базе в соответствии с результатами построения отчета + UnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. + AIAuditService audittservice = mainUnityContainer.Resolve(); + audittservice.RatifyAuditOperation( + correct ? tExecutionVariant.Executed : tExecutionVariant.Failed, + new List { auditOperationId.Value }, + false); +} +``` + +## Результат + +Теперь при попытке создания отчета в базе данных аудита создастся соответствующая запись. Статус выполнения операции будет зависеть от успешности её выполнения. + +### Измененный метод + +```csharp +public static Отчет СоздатьОтчетПоКлиенту(Клиент клиент) +{ + // Занести данные о начале операции создания отчета в подсистему аудита + var auditParams = new CustomAuditParameters + { + CustomAuditOperation = string.Format("Создание отчета по клиенту {0} (ID: {1})", клиент.ФИО, клиент.__PrimaryKey), + ExecutionResult = tExecutionVariant.Unknown, + OperationTime = DateTime.Now, + UseDefaultWriteMode = true + }; + + // Записать операцию аудита в базу и запоминить ID созданной записи + UnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. + AIAuditService audittservice = mainUnityContainer.Resolve(); + Guid? auditOperationId = audittservice.WriteCustomAuditOperation(auditParams, true); + + var report = new Отчет(); + bool correct = true; + + try + { + // Создать отчет ... + } + catch(Exception ex) + { + // Записать ошибку в лог ... + + // Запоминить факт возникновения ошибки + correct = false; + } + finally + { + // Обновить статус операции в базе в соответствии с результатами построения отчета + UnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. + AIAuditService audittservice = mainUnityContainer.Resolve(); + audittservice.RatifyAuditOperation( + correct ? tExecutionVariant.Executed : tExecutionVariant.Failed, + new List { auditOperationId.Value }, + false); + } + + return report; +} +``` + +### Web-интерфейс + +После попытки создания двух отчетов, одна из которых прошла успешно, а вторая неудачно: + +Форма просмотра записей аудита (частично): +![Изображение](/images/img/page/AuditWebApiExample/AuditWebApiWolv.PNG) + +Форма просмотра деталей записи аудита: +![Изображение](/images/img/page/AuditWebApiExample/AuditWebApiE.PNG) diff --git a/pages/products/flexberry-orm/authority-audit/efs_AuditWinExampleManual.ru.md b/pages/products/flexberry-orm/authority-audit/efs_AuditWinExampleManual.ru.md index f28cfaf93..7bc01e677 100644 --- a/pages/products/flexberry-orm/authority-audit/efs_AuditWinExampleManual.ru.md +++ b/pages/products/flexberry-orm/authority-audit/efs_AuditWinExampleManual.ru.md @@ -1,55 +1,71 @@ ---- -title: Пример подключения аудита к существующему Win-приложению без использования перегенерации проекта. -sidebar: ember-flexberry-security_sidebar -keywords: Flexberry Audit -toc: true -permalink: ru/efs_audit-win-example-manual.html -folder: products/ember-flexberry-security/backend/ -lang: ru ---- - -# Подключение подсистемы аудита без полной перегенерации проекта -Алгоритм подключения: -# Перегенерировать объекты -# Внести изменения в app.config -# Добавить инициализацию аудита в main -# Подключить недостающие сборки - -# Перегенерация объектов -Без перегенерации объектов все равно не обойтись, так как настройки аудита хранятся в классах (подробнее см. [здесь](fa_audit-web.html) в разделе "Настройка класса"). - -# Внесение изменений в app.config -В блок `Configuration` - `appSettings` необходимо добавить следующие строчки: -```xml - - - - - - -``` -А также -```xml - - -``` -указав заместо ... необходимые значения наименования Win-сервиса и строки подключения к базе аудита. - -# Подключение аудита в main -необходимо добавить вызов инициализации с помощью [Инициализация аудита](efs_audit-setter.html). -``` - -// *** Start programmer edit section *** (TestFS Main()) -ICSSoft.STORMNET.Windows.Forms.WinApplication.SetUICultureAsRussian(); - -// Инициализация сервиса аудита -AuditSetter.InitAuditService(DataServiceProvider.DataService); -// *** End programmer edit section *** (TestFS Main()) -``` - -# Подключение сборок -# Подключить к приложению и `DesktopCustomizer` ICSSoft.STORMNET.Business.Audit.dll. -# К приложению подключить сборки Security. - -# См. также -[Пример подключения аудита к существующему Web-приложению без использования перегенерации проекта.](fa_audit-web-example-manual.html) +--- +title: Пример подключения аудита к существующему Win-приложению без использования перегенерации проекта. +sidebar: ember-flexberry-security_sidebar +keywords: Flexberry Audit +toc: true +permalink: ru/efs_audit-win-example-manual.html +folder: products/ember-flexberry-security/backend/ +lang: ru +--- + +## Подключение подсистемы аудита без полной перегенерации проекта + +Алгоритм подключения: + +1. Перегенерировать объекты +2. Внести изменения в app.config +3. Добавить инициализацию аудита в main +4. Подключить недостающие сборки + +## Перегенерация объектов + +Без перегенерации объектов все равно не обойтись, так как настройки аудита хранятся в классах (подробнее см. [здесь](fa_audit-web.html) в разделе "Настройка класса"). + +## Внесение изменений в app.config + +В блок `Configuration` - `appSettings` необходимо добавить следующие строчки: + +```xml + + + + + + +``` + +А также + +```xml + + +``` + +указав заместо ... необходимые значения наименования Win-сервиса и строки подключения к базе аудита. + +## Подключение аудита в main + +необходимо добавить вызов инициализации с помощью [Инициализация аудита](efs_audit-setter.html). + +```csharp +// \*** Start programmer edit section *** (TestFS Main()) +ICSSoft.STORMNET.Windows.Forms.WinApplication.SetUICultureAsRussian(); + +// Инициализация сервиса аудита +IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. +IDataService ds = mainUnityContainer.Resolve(); +AuditSetter.InitAuditService(ds); +// \*** End programmer edit section *** (TestFS Main()) +``` + +## Подключение сборок + +## Подключить к приложению DesktopCustomizer ICSSoft.STORMNET.Business.Audit.dll + +ICSSoft.STORMNET.Business.Audit.dll + +## К приложению подключить сборки Security + +## См. также + +[Пример подключения аудита к существующему Web-приложению без использования перегенерации проекта.](fa_audit-web-example-manual.html) diff --git a/pages/products/flexberry-orm/authority-audit/efs_AuditWinService.ru.md b/pages/products/flexberry-orm/authority-audit/efs_AuditWinService.ru.md index 72857c574..5d71a6f81 100644 --- a/pages/products/flexberry-orm/authority-audit/efs_AuditWinService.ru.md +++ b/pages/products/flexberry-orm/authority-audit/efs_AuditWinService.ru.md @@ -1,88 +1,91 @@ ---- -title: Windows-сервис аудита -sidebar: ember-flexberry-security_sidebar -keywords: Flexberry Audit -toc: true -permalink: ru/efs_audit-win-service.html -lang: ru ---- - -(((Данная статья относится к новому аудиту))) - -# Аудит -Что такое аудит можно узнать в [этой статье](fa_audit-web.html). - - -# Сервис Аудита -Отдельный сервис Аудита предоставляет те же возможности, что и встроенный в приложение аудит, но он вынесен в виде отдельного Windows-сервиса. (данный сервис доработан в версии после 02.10.2013) - -# Подключение к сервису аудита -Для подключения к сервису необходимо: - -1. Добавить в файл конфигурации приложения ключ `AuditWinServiceUrl`, определяющий url, где располагается сервис. - -```xml - -``` -Выше указан адрес для примера. В реальной ситуации адрес необходимо брать из конфигурационного файла сервиса: -```xml - - - - - - - - - - - - - - - -``` - -2. Подготовить сборку с объектами, аудит которых будет производиться. Сборка нужна только для работы метода [WriteCommonAuditOperation](efs_audit-web-api.html), остальные методы записи аудита (в том числе метод записи аудита для собственных объектов и операций) не требуют сборок с объектами. - -((( -Обратите внимание, что сборка с объектами должна быть собрана для версии .Net Framework версии 3.5. -))) - -Подготовленную сборку необходимо скопировать в папку "ObjectAssemblies", расположенную рядом с сервисом аудита. - -3. Сконфигурировать настройки по работе с базой данных (есть [отдельная статья, определяющая механизм определения настроек соединения с БД при аудите](efs_data-service-for-audit.html)). - -Для этого нужно в конфиг-файле приложения указать следующие настройки (данные настройки приведены для примера и могут отличаться в конкретном приложении): -```xml - - - -``` - -Если `IsAuditDatabaseLocal = false`, то в конфиге сервиса будет искаться строка подключения, задаваемая параметром `AuditConnectionStringName` (то есть в данном случае - "`AuditConnString`"). -```xml - - - -``` - -Тип сервиса данных всегда ищется в конфиг-файле по ключу `<Имя строки соединения>_DSType` (если такой записи нет, то берётся сервис данных, указанных в настройке "`DefaultDSType`", а если и это не помогло, то используется сервис данных, указанный в `DataServiceProvider.DataService`). - -```xml - - - - - - -``` - -Если `IsAuditDatabaseLocal = true`, то получение имени имени строки соединения происходит по особой схеме: имя ищется среди [AuditDSSettings](fa_audit-web.html). Имя сервиса по умолчанию определено как `<AppNameForAudit>_<AuditConnectionStringName>` (в нашем случае - это "`TestFS_AuditConnString`"). - -```xml - - - -``` - +--- +title: Windows-сервис аудита +sidebar: ember-flexberry-security_sidebar +keywords: Flexberry Audit +toc: true +permalink: ru/efs_audit-win-service.html +lang: ru +--- + +> Данная статья относится к новому аудиту + +## Аудит + +Что такое аудит можно узнать в [этой статье](fa_audit-web.html). + +# Сервис Аудита + +Отдельный сервис Аудита предоставляет те же возможности, что и встроенный в приложение аудит, но он вынесен в виде отдельного Windows-сервиса. (данный сервис доработан в версии после 02.10.2013) + +# Подключение к сервису аудита + +Для подключения к сервису необходимо: + +1.Добавить в файл конфигурации приложения ключ `AuditWinServiceUrl`, определяющий url, где располагается сервис. + +```xml + +``` + +Выше указан адрес для примера. В реальной ситуации адрес необходимо брать из конфигурационного файла сервиса: + +```xml + + + + + + + + + + + + + + + +``` + +2.Подготовить сборку с объектами, аудит которых будет производиться. Сборка нужна только для работы метода [WriteCommonAuditOperation](efs_audit-web-api.html), остальные методы записи аудита (в том числе метод записи аудита для собственных объектов и операций) не требуют сборок с объектами. + +> Сборка с объектами должна быть собрана для версии .Net Framework версии 3.5. + +Подготовленную сборку необходимо скопировать в папку "ObjectAssemblies", расположенную рядом с сервисом аудита. + +3.Сконфигурировать настройки по работе с базой данных (есть [отдельная статья, определяющая механизм определения настроек соединения с БД при аудите](efs_data-service-for-audit.html)). + +Для этого нужно в конфиг-файле приложения указать следующие настройки (данные настройки приведены для примера и могут отличаться в конкретном приложении): + +```xml + + + +``` + +Если `IsAuditDatabaseLocal = false`, то в конфиге сервиса будет искаться строка подключения, задаваемая параметром `AuditConnectionStringName` (то есть в данном случае - "`AuditConnString`"). + +```xml + + + +``` + +Тип сервиса данных всегда ищется в конфиг-файле по ключу `<Имя строки соединения>_DSType` (если такой записи нет, то берётся сервис данных, указанных в настройке "`DefaultDSType`", а если и это не помогло, то используется сервис данных, указанный в `IDataService`). + +```xml + + + + + + +``` + +Если `IsAuditDatabaseLocal = true`, то получение имени имени строки соединения происходит по особой схеме: имя ищется среди [AuditDSSettings](fa_audit-web.html). Имя сервиса по умолчанию определено как `<AppNameForAudit>_<AuditConnectionStringName>` (в нашем случае - это "`TestFS_AuditConnString`"). + +```xml + + + +``` diff --git a/pages/products/flexberry-orm/authority-audit/efs_DataServiceForAudit.ru.md b/pages/products/flexberry-orm/authority-audit/efs_DataServiceForAudit.ru.md index cb2e80913..1c07eabd0 100644 --- a/pages/products/flexberry-orm/authority-audit/efs_DataServiceForAudit.ru.md +++ b/pages/products/flexberry-orm/authority-audit/efs_DataServiceForAudit.ru.md @@ -1,64 +1,64 @@ ---- -title: Механизм определения настроек подключения к БД при работе аудита -sidebar: ember-flexberry-security_sidebar -keywords: Flexberry Audit, БД -toc: true -permalink: ru/efs_data-service-for-audit.html -lang: ru ---- - -Данная статья относится к [новому аудиту](fa_audit-web.html). - -# Механизм определения строки подключения при работе аудита -'''Механизм работает в версиях сборок после 27.01.2015.''' - -При ведении аудита важным является определить, как и в какую БД будут записываться данные аудита. Для этого определяется имя строки подключения к аудиту и тип [сервиса данных](fo_data-service.html). - -## Определение имени строки подключения -Определение имени строки подключения происходит по следующему алгоритму: - -1. Из настроек аудита из класса ([AuditClassSetting](efs_keep-and-use-audit-settings.html)) берётся настройка `AuditClassConnectionStringName`. - -```cs -public class FirstClass : ICSSoft.STORMNET.DataObject, IDataObjectWithAuditFields -{ - ... - - /// - /// Audit class settings. - /// - public class AuditSettings - { - /// - /// Имя строки соединения с БД, куда необходимо писать аудит. - /// - public static string AuditClassConnectionStringName = "FirstClassConnectionStringName"; - } -} -``` - -Если `AuditClassConnectionStringName` определено в настройках аудита класса и значение является непустой последовательностью символов, то оно берётся в качестве имени строки подключения. - -2. Если предыдущим способом имя строки подключения не было определено, то берётся настройка [IsDatabaseLocal](efs_keep-and-use-audit-settings.html) (см. также [следующую статью](efs_audit-win-service.html)). - -2.1. Если `IsDatabaseLocal = false`, то в качестве имени строки соединения берётся значение [AuditConnectionStringName](efs_keep-and-use-audit-settings.html). - -2.2. Если `IsDatabaseLocal = true`, то происходит поиск по структурам [AuditDSSetting](efs_keep-and-use-audit-settings.html). - -Считается, что если `IsDatabaseLocal = true`, то запись аудита будет производиться в "текущую" БД посредством "текущего" [сервиса данных](fo_data-service.html) (понятие "текущий" условно, поскольку в метод определения имени строки подключения тип "текущего" [сервиса данных](fo_data-service.html) может попасть различными способами). - -Если "текущий" [сервис данных](fo_data-service.html) некорректен, то в качестве имени строки соединения используется значение [ConnStringName](efs_keep-and-use-audit-settings.html) из первой `AuditDSSetting` из массива `AuditDSSettings` ([имя строки соединения по умолчанию определено как <AppNameForAudit>_<AuditConnectionStringName>](efs_audit-setter.html)). - -Иначе среди массива `AuditDSSettings` ищется `AuditDSSetting`, где [ConnString](efs_keep-and-use-audit-settings.html) равно строке соединения "текущего" [сервиса данных](fo_data-service.html), а [DataServiceType](efs_keep-and-use-audit-settings.html) - типу "текущего" [сервиса данных](fo_data-service.html), и значение первой найденной `ConnStringName` будет искомым именем строки соединения для аудита. - -Реализация интерфейса [IAudit](efs_i-audit.html) `ICSSoft.STORMNET.Business.Audit.Audit` обрабатывает полученное имя строки соединения следующим образом: -# Производится поиск строки соединения по имени среди доступных в файле конфигурации. -# Если строка соединения не была найдена, то используется строка соединения из [DataServiceProvider.DataService](fo_ds-provider.html). - -## Определение типа сервиса данных -Тип [сервиса данных](fo_data-service.html), посредством которого будет записываться аудит, не определяется на этапе подготовки данных для записи в аудит. Тип определяется уже в реализации интерфейса `IAudit`. - -Реализация интерфейса `IAudit` `ICSSoft.STORMNET.Business.Audit.Audit` определяет тип сервиса данных следующим образом (см. также [следующую статью](efs_audit-win-service.html)): -# Тип сервиса данных всегда ищется в конфиг-файле по ключу <Имя строки соединения>_DSType. -# Если такой записи нет, то берётся сервис данных, указанных в настройке "DefaultDSType". -# Иначе используется тип сервиса данных [DataServiceProvider.DataService](fo_ds-provider.html). +--- +title: Механизм определения настроек подключения к БД при работе аудита +sidebar: ember-flexberry-security_sidebar +keywords: Flexberry Audit, БД +toc: true +permalink: ru/efs_data-service-for-audit.html +lang: ru +--- + +Данная статья относится к [новому аудиту](fa_audit-web.html). + +## Механизм определения строки подключения при работе аудита + +При ведении аудита важным является определить, как и в какую БД будут записываться данные аудита. Для этого определяется имя строки подключения к аудиту и тип [сервиса данных](fo_data-service.html). + +## Определение имени строки подключения + +Определение имени строки подключения происходит по следующему алгоритму: + +1.Из настроек аудита из класса ([AuditClassSetting](efs_keep-and-use-audit-settings.html)) берётся настройка `AuditClassConnectionStringName`. + +```cs +public class FirstClass : ICSSoft.STORMNET.DataObject, IDataObjectWithAuditFields +{ +... + /// + /// Audit class settings. + /// + public class AuditSettings + { + /// + /// Имя строки соединения с БД, куда необходимо писать аудит. + /// + public static string AuditClassConnectionStringName = "FirstClassConnectionStringName"; + } +} +``` + +Если `AuditClassConnectionStringName` определено в настройках аудита класса и значение является непустой последовательностью символов, то оно берётся в качестве имени строки подключения. + +2.Если предыдущим способом имя строки подключения не было определено, то берётся настройка [IsDatabaseLocal](efs_keep-and-use-audit-settings.html) (см. также [следующую статью](efs_audit-win-service.html)). + +2.1. Если `IsDatabaseLocal = false`, то в качестве имени строки соединения берётся значение [AuditConnectionStringName](efs_keep-and-use-audit-settings.html). + +2.2. Если `IsDatabaseLocal = true`, то происходит поиск по структурам [AuditDSSetting](efs_keep-and-use-audit-settings.html). + +Считается, что если `IsDatabaseLocal = true`, то запись аудита будет производиться в "текущую" БД посредством "текущего" [сервиса данных](fo_data-service.html) (понятие "текущий" условно, поскольку в метод определения имени строки подключения тип "текущего" [сервиса данных](fo_data-service.html) может попасть различными способами). + +Если "текущий" [сервис данных](fo_data-service.html) некорректен, то в качестве имени строки соединения используется значение [ConnStringName](efs_keep-and-use-audit-settings.html) из первой `AuditDSSetting` из массива `AuditDSSettings` ([имя строки соединения по умолчанию определено как <AppNameForAudit>_<AuditConnectionStringName>](efs_audit-setter.html)). + +Иначе среди массива `AuditDSSettings` ищется `AuditDSSetting`, где [ConnString](efs_keep-and-use-audit-settings.html) равно строке соединения "текущего" [сервиса данных](fo_data-service.html), а [DataServiceType](efs_keep-and-use-audit-settings.html) - типу "текущего" [сервиса данных](fo_data-service.html), и значение первой найденной `ConnStringName` будет искомым именем строки соединения для аудита. + +Реализация интерфейса [IAudit](efs_i-audit.html) `ICSSoft.STORMNET.Business.Audit.Audit` обрабатывает полученное имя строки соединения следующим образом: + +Производится поиск строки соединения по имени среди доступных в файле конфигурации. + +## Определение типа сервиса данных + +Тип [сервиса данных](fo_data-service.html), посредством которого будет записываться аудит, не определяется на этапе подготовки данных для записи в аудит. Тип определяется уже в реализации интерфейса `IAudit`. + +Реализация интерфейса `IAudit` `ICSSoft.STORMNET.Business.Audit.Audit` определяет тип сервиса данных следующим образом (см. также [следующую статью](efs_audit-win-service.html)): + +1. Тип сервиса данных всегда ищется в конфиг-файле по ключу <Имя строки соединения>_DSType. +2. Если такой записи нет, то берётся сервис данных, указанных в настройке "DefaultDSType". diff --git a/pages/products/flexberry-orm/authority-audit/efs_SecurityManager.ru.md b/pages/products/flexberry-orm/authority-audit/efs_SecurityManager.ru.md index be8db30cc..fc0cc3174 100644 --- a/pages/products/flexberry-orm/authority-audit/efs_SecurityManager.ru.md +++ b/pages/products/flexberry-orm/authority-audit/efs_SecurityManager.ru.md @@ -97,7 +97,7 @@ lang: ru - + diff --git a/pages/products/flexberry-orm/authority-audit/efs_security-rights-objects.ru.md b/pages/products/flexberry-orm/authority-audit/efs_security-rights-objects.ru.md index 7ba8ee404..b13800f5b 100644 --- a/pages/products/flexberry-orm/authority-audit/efs_security-rights-objects.ru.md +++ b/pages/products/flexberry-orm/authority-audit/efs_security-rights-objects.ru.md @@ -1,197 +1,197 @@ ---- -title: Работа с полномочиями на объекты -sidebar: ember-flexberry-security_sidebar -keywords: Flexberry Security, Ключевые понятия -toc: true -permalink: ru/efs_security-rights-objects.html -lang: ru ---- - -## Задание полномочий на объекты - -Рассмотрим задачу задания полномочий на объекты на примере следующей задачи. Есть класс Document. Необходимо иметь возможность на каждый отдельный Document задавать индивидуальные полномочия. - -((( -Данное решение не рекомендуется использовать в реальных проектах до выхода стабильных версий пакетов, возможно оно будет изменено. -" %} - -Чтобы задать полномочия на чтение (то есть [DataService|сервис данных) не будет вычитывать объекты, на которые не заданы полномочия) на объекты требуется задать в полномочиях соответствующие фильтры. Например, если мы хотим, чтобы пользователю User1 был доступен на чтение документ Document1, то необходимо создать Permition, где агентом является User1, а субъектом - класс Document, создать Access с типом доступа Read и наложить фильтр, что первичный ключ равен первичному ключу объекта Document1. Если потребуется дополнительно дать права на Document2, то нужно внести изменения в фильтр, что первичный ключ может иметь значение первичного ключа Document1 или Document2. - -Как это реализовать: - -1. Обновить пакет Flexberry ORM до версии не ниже 2.1.0-alpha01. - -Обновить пакет Flexberry Security до версии не ниже 1.5.0-alpha01. - -Прописать в секцию unity определение для ISecurityManager: -```xml - - -
- ... - - - - - - - - - - - - - - ... - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ... - -``` - -2. Удостовериться, что у класса Document стоит [AccessType|тип доступа this). - -3. Для удобного задания полномочий реализуем форму вида: - -[imageauto||{UP(SecurityRightsOnObjects)}SetPermissionsOnObjectForm.png) - -На такой форме можно выбрать: -* объект типа Document, на который мы задаём полномочия; -* пользователя, для которого задаются полномочия; -* тип доступа; -* добавляем или удаляем доступ (в зависимости от галочки). - -4. Поскольку объекты полномочий расположены в БД полномочий, то определяем специальный [DataService|сервис данных). - -``` csharp -/// -/// Закэшированное значение сервиса данных для работы с полномочиями. -/// -private static IDataService _securityDataService = null; - -/// -/// Сервис данных для работы с полномочиями. -/// После первого получения кэшируется. -/// -private static IDataService SecurityDataService -{ - get - { - if (_securityDataService == null) - { - IUnityContainer container = UnityFactory.GetContainer(); - _securityDataService = container.Resolve("SecurityManagerDataService"); - } - - return _securityDataService; - } -} -``` - -5. Чтобы выбранные полномочия менялись при нажатии на кнопку "Сохранить", пишем соответствующую логику. - -``` csharp -/// -/// Нетривиальная логика сохранения объекта. -/// -/// Объект данных, который сохранился. -protected override DataObject SaveObject() -{ - // Вычитываем выбранное имя пользователя. - string agentName = SelectUserControl.Items[SelectUserControl.SelectedIndex).Value; - - // Определяем выбранный документ. - Document selectedDocument = DataObject.Document; - - CurrentUserService.IUser user = new User() { Login = agentName }; - - // Определяем тип доступа. - string selectedAccessTypeName = SelectAccessType.Items[SelectAccessType.SelectedIndex).Value; - - // Определяем, добавляем или удаляем права. - bool addAccess = AddAccessCheckBox.Checked; - tTypeAccess selectedTypeAccess; - - // Если ошибка в заполненных данных, то выводим ошибку. - if (string.IsNullOrEmpty(agentName) || !Enum.TryParse(selectedAccessTypeName, out selectedTypeAccess)) - { - WebErrorBoxRiser.Rise(new Exception("Указанные данные некорректны."), false); - return null; - } - - SecurityManager securityManager = new SecurityManager(SecurityDataService, true, true, false); - - if (addAccess) - { - securityManager.AddPermissionToObject(user, selectedTypeAccess, selectedDocument); - } - else - { - securityManager.RemovePermissionToObject(user, selectedTypeAccess, selectedDocument); - } - - return null; -} -``` - -Теперь при задании на какого-то пользователя специфичных прав ему будет доступно просматривать только соответствующие строки. - -## Проверка полномочий, заданных на объект - -Чтобы проверить, удовлетворяет ли объект заданным фильтрами полномочий, можно воспользоваться следующей функциональностью: - -``` csharp -ISecurityManager securityManager = DataServiceProvider.DataService.SecurityManager; -bool hasAccess = securityManager.AccessObjectCheck(objectTocheck, tTypeAccess.Insert, true); -``` - -Сначала в примере происходит получение текущей инстанции `ISecurityManager`, установленной в текущий [DataService|сервис данных) (требуется, чтобы при этом менеджер полномочий был настроен на проверку полномочий на объекты (например, с помощью конфига, как показано выше); если это не так, то необходимую инстанцию менеджера полномочий можно создать с помощью программного кода). - -Далее в метод менеджера полномочий передаётс: -* объект, полномочия на который проверяются (может быть передан любой объект, в этом случае происходит проверка доступа на тип объекта, но если передан [DataObject|объект данных), то проверка происходит и на сам объект с учётом заданных ограничений), -* тип операции, полномочия на которую требуется проверять, -* флаг, определяющий, требуется ли кидать исключение, если отсутствуют полномочия на объект. - -((( -На настоящий момент поддерживается проверка полномочий на минимальное количество функций ограничения (точно поддерживаются только ограничения, создаваемые выше). -" %} +--- +title: Работа с полномочиями на объекты +sidebar: ember-flexberry-security_sidebar +keywords: Flexberry Security, Ключевые понятия +toc: true +permalink: ru/efs_security-rights-objects.html +lang: ru +--- + +## Задание полномочий на объекты + +Рассмотрим задачу задания полномочий на объекты на примере следующей задачи. Есть класс Document. Необходимо иметь возможность на каждый отдельный Document задавать индивидуальные полномочия. + +> Данное решение не рекомендуется использовать в реальных проектах до выхода стабильных версий пакетов, возможно оно будет изменено. + +Чтобы задать полномочия на чтение на объекты требуется задать в полномочиях соответствующие фильтры. Например, если мы хотим, чтобы пользователю User1 был доступен на чтение документ Document1, то необходимо создать Permition, где агентом является User1, а субъектом - класс Document, создать Access с типом доступа Read и наложить фильтр, что первичный ключ равен первичному ключу объекта Document1. Если потребуется дополнительно дать права на Document2, то нужно внести изменения в фильтр, что первичный ключ может иметь значение первичного ключа Document1 или Document2. + +Как это реализовать: + +1.Обновить пакет Flexberry ORM до версии не ниже 2.1.0-alpha01. + +Обновить пакет Flexberry Security до версии не ниже 1.5.0-alpha01. + +Прописать в секцию unity определение для ISecurityManager: + +```xml + + +
+ ... + + + + + + + + + + + + + + ... + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ... + +``` + +2.Удостовериться, что у класса Document стоит [AccessType|тип доступа this). + +3.Для удобного задания полномочий реализуем форму вида: + +![SetPermissionsOnObjectForm](/images/pages/products/flexberry-aspnet/controls/wolv/SetPermissionsOnObjectForm.png) + +На такой форме можно выбрать: + +* объект типа Document, на который мы задаём полномочия; +* пользователя, для которого задаются полномочия; +* тип доступа; +* добавляем или удаляем доступ (в зависимости от галочки). + +4.Поскольку объекты полномочий расположены в БД полномочий, то определяем специальный [DataService|сервис данных). + +``` csharp +/// +/// Закэшированное значение сервиса данных для работы с полномочиями. +/// +private static IDataService _securityDataService = null; + +/// +/// Сервис данных для работы с полномочиями. +/// После первого получения кэшируется. +/// +private static IDataService SecurityDataService +{ + get + { + if (_securityDataService == null) + { + IUnityContainer container = UnityFactory.GetContainer(); + _securityDataService = container.Resolve("SecurityManagerDataService"); + } + + return _securityDataService;} +} +``` + +5.Чтобы выбранные полномочия менялись при нажатии на кнопку "Сохранить", пишем соответствующую логику. + +``` csharp +/// +/// Нетривиальная логика сохранения объекта. +/// +/// Объект данных, который сохранился. +protected override DataObject SaveObject() +{ + // Вычитываем выбранное имя пользователя. + string agentName = SelectUserControl.Items[SelectUserControl.SelectedIndex].Value; + + // Определяем выбранный документ. + Document selectedDocument = DataObject.Document; + + CurrentUserService.IUser user = new User() { Login = agentName }; + + // Определяем тип доступа. + string selectedAccessTypeName = SelectAccessType.Items[SelectAccessType.SelectedIndex].Value; + + // Определяем, добавляем или удаляем права. + bool addAccess = AddAccessCheckBox.Checked; + tTypeAccess selectedTypeAccess; + + // Если ошибка в заполненных данных, то выводим ошибку. + if (string.IsNullOrEmpty(agentName) || !Enum.TryParse(selectedAccessTypeName, out selectedTypeAccess)) + { + WebErrorBoxRiser.Rise(new Exception("Указанные данные некорректны."), false); + return null; + } + + SecurityManager securityManager = new SecurityManager(SecurityDataService, true, true, false); + + if (addAccess) + { + securityManager.AddPermissionToObject(user, selectedTypeAccess, selectedDocument); + } + else + { + securityManager.RemovePermissionToObject(user, selectedTypeAccess, selectedDocument); + } + + return null; +} +``` + +Теперь при задании на какого-то пользователя специфичных прав ему будет доступно просматривать только соответствующие строки. + +## Проверка полномочий, заданных на объект + +Чтобы проверить, удовлетворяет ли объект заданным фильтрами полномочий, можно воспользоваться следующей функциональностью: + +``` csharp +IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. +IDataService ds = mainUnityContainer.Resolve(); +ISecurityManager securityManager = ds.SecurityManager; +bool hasAccess = securityManager.AccessObjectCheck(objectTocheck, tTypeAccess.Insert, true); +``` + +Сначала в примере происходит получение текущей инстанции `ISecurityManager`, установленной в текущий сервис данных (требуется, чтобы при этом менеджер полномочий был настроен на проверку полномочий на объекты (например, с помощью конфига, как показано выше); если это не так, то необходимую инстанцию менеджера полномочий можно создать с помощью программного кода). + +Далее в метод менеджера полномочий передаётся: + +* объект, полномочия на который проверяются (может быть передан любой объект, в этом случае происходит проверка доступа на тип объекта, но если передан объект данных, то проверка происходит и на сам объект с учётом заданных ограничений), +* тип операции, полномочия на которую требуется проверять, +* флаг, определяющий, требуется ли кидать исключение, если отсутствуют полномочия на объект. + +> На настоящий момент поддерживается проверка полномочий на минимальное количество функций ограничения (точно поддерживаются только ограничения, создаваемые выше). diff --git a/pages/products/flexberry-orm/business-servers/fo_cascade-delete.ru.md b/pages/products/flexberry-orm/business-servers/fo_cascade-delete.ru.md index 73e95ac30..8723da66b 100644 --- a/pages/products/flexberry-orm/business-servers/fo_cascade-delete.ru.md +++ b/pages/products/flexberry-orm/business-servers/fo_cascade-delete.ru.md @@ -12,7 +12,7 @@ lang: ru Пусть дана следующая [диаграмма](fd_class-diagram.html): -![](/images/pages/products/flexberry-orm/business-servers/kredit-diagramm.png) +![kredit-diagramm](/images/pages/products/flexberry-orm/business-servers/kredit-diagramm.png) Если в базе данных есть объекты типа `Клиент`, ссылающиеся на `Адрес`, то без дополнительных настроек при попытке удаления объекта типа `Адрес` произойдёт ошибка. База данных не даст удалить такой объект. @@ -65,37 +65,39 @@ lang: ru Необходимо доработать диаграмму классов таким образом, чтобы она поддерживала фиктивное удаление: добавить поле `Актуально:bool`. -![](/images/pages/products/flexberry-orm/business-servers/kredit-diagramm-aktualno.png) +![kredit-diagramm-aktualno](/images/pages/products/flexberry-orm/business-servers/kredit-diagramm-aktualno.png) Добавить логику в бизнес-сервера объектов (на примере `Адреса`): ```csharp if (UpdatedObject.GetStatus() == ObjectStatus.Deleted) { - // Не дадим объекту удалиться, но выставим флаг Актуальности. - UpdatedObject.SetStatus(ObjectStatus.Altered); - UpdatedObject.Актуально = false; - - // Найдем все объекты, ссылающиеся на "удаляемый" и удалим их. - var ds = (SQLDataService)DataServiceProvider.DataService; - var klients = - ds.Query<Клиент>(Клиент.Views.КлиентE) - .Where(k => k.Прописка.__PrimaryKey == UpdatedObject.__PrimaryKey); - foreach (var k in klients) - { - k.SetStatus(ObjectStatus.Deleted); - } - - return klients.ToArray(); + // Не дадим объекту удалиться, но выставим флаг Актуальности. + UpdatedObject.SetStatus(ObjectStatus.Altered); + UpdatedObject.Актуально = false; + + // Найдем все объекты, ссылающиеся на "удаляемый" и удалим их. + IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. + IDataService ds = mainUnityContainer.Resolve(); + var klients = + ds.Query<Клиент>(Клиент.Views.КлиентE) + .Where(k => k.Прописка.__PrimaryKey == UpdatedObject.__PrimaryKey); + foreach (var k in klients) + { + k.SetStatus(ObjectStatus.Deleted); + } + +return klients.ToArray(); } ``` -{% include note.html content="Внимание! Cсылающиеся объекты отправленные на удаление, но они точно также перехватятся в своем бизнес-сервере и не удалятся." %} +> Внимание! Cсылающиеся объекты отправленные на удаление, но они точно также перехватятся в своем бизнес-сервере и не удалятся." Далее, чтобы пользователю не выводились "удаленные" данные при просмотре списка объектов, требуется на соответствующий контрол наложить ограничение вида: ``` csharp -var ds = (MSSQLDataService)DataServiceProvider.DataService; +IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. +IDataService ds = mainUnityContainer.Resolve(); IQueryable<Клиент> limit1 = ds.Query<Адрес>(Адрес.Views.АдресL).Where(Address => Address.Актуально); Function onlyActual = LinqToLcs.GetLcs(limit1.Expression, Адрес.Views.АдресL).LimitFunction; -``` \ No newline at end of file +``` diff --git a/pages/products/flexberry-orm/business-servers/fo_delete-cancel.ru.md b/pages/products/flexberry-orm/business-servers/fo_delete-cancel.ru.md index 4277a87a4..d4da30242 100644 --- a/pages/products/flexberry-orm/business-servers/fo_delete-cancel.ru.md +++ b/pages/products/flexberry-orm/business-servers/fo_delete-cancel.ru.md @@ -18,11 +18,11 @@ lang: ru Пусть дана следующая диаграмма: -![](/images/pages/products/flexberry-orm/business-servers/kredit-diagramm.png) +![kredit-diagramm](/images/pages/products/flexberry-orm/business-servers/kredit-diagramm.png) Если в базе данных есть объекты типа `Клиент`, ссылающиеся на него, то при попытке удаления объекта типа `Адрес` будет выведена ошибка: -![](/images/pages/products/flexberry-orm/business-servers/delete-error.png) +![delete-error](/images/pages/products/flexberry-orm/business-servers/delete-error.png) База данных не даст удалить такой объект, а пользователю выдастся неинформативное сообщение. @@ -42,7 +42,8 @@ lang: ru if (UpdatedObject.GetStatus() == ObjectStatus.Deleted) { // Найдем количество клиентов, ссылающихся на удаляемый адрес. - var ds = (MSSQLDataService)DataServiceProvider.DataService; + IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. + IDataService ds = mainUnityContainer.Resolve(); var clientsCount = ds.Query<Клиент>(Клиент.Views.КлиентE).Where(k => k.Прописка.__PrimaryKey == UpdatedObject.__PrimaryKey).Count(); // Если клиентов не 0, выкинем исключение. @@ -55,6 +56,6 @@ if (UpdatedObject.GetStatus() == ObjectStatus.Deleted) В результате, при попытке удалить адрес, по которому прописаны клиенты, пользователю выдастся следующее сообщение: -![](/images/pages/products/flexberry-orm/business-servers/delete-error-plus.png) +![delete-error-plus](/images/pages/products/flexberry-orm/business-servers/delete-error-plus.png) Сообщение изменилось на более информативное. diff --git a/pages/products/flexberry-orm/business-servers/fo_unique-data-check.ru.md b/pages/products/flexberry-orm/business-servers/fo_unique-data-check.ru.md index c6768822c..f196c758f 100644 --- a/pages/products/flexberry-orm/business-servers/fo_unique-data-check.ru.md +++ b/pages/products/flexberry-orm/business-servers/fo_unique-data-check.ru.md @@ -14,7 +14,7 @@ lang: ru ## Пример -![](/images/pages/products/flexberry-orm/additional-features/templates.PNG) +![templates](/images/pages/products/flexberry-orm/additional-features/templates.PNG) Требуется проверять уникальность введенного номера кредитной карты. @@ -24,7 +24,8 @@ lang: ru Код с применением [LinqProvider](fo_linq-provider.html): ```csharp -var ds = (SQLDataService)DataServiceProvider.DataService; +IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. +IDataService ds = mainUnityContainer.Resolve(); var кредитныеКарты = ds.Query<КредитнаяКарта>(КредитнаяКарта.Views.КредитнаяКартаE) .Count(k => k.Клиент.__PrimaryKey == UpdatedObject.Клиент.__PrimaryKey && k.Номер == UpdatedObject.Номер); @@ -35,7 +36,8 @@ var кредитныеКарты = ds.Query<КредитнаяКарта>(Кре Следует доработать условие, добавив сравнение с текущей картой, используя `LinqProvider`: ```csharp -var ds = (SQLDataService)DataServiceProvider.DataService; +IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. +IDataService ds = mainUnityContainer.Resolve(); var кредитныеКарты = ds.Query<КредитнаяКарта>(КредитнаяКарта.Views.КредитнаяКартаE) .Count(k => k.Клиент.__PrimaryKey == UpdatedObject.Клиент.__PrimaryKey && k.Номер == UpdatedObject.Номер diff --git a/pages/products/flexberry-orm/data-object/fo_actions-saving-object.ru.md b/pages/products/flexberry-orm/data-object/fo_actions-saving-object.ru.md index 9bb7f9f39..af50596d9 100644 --- a/pages/products/flexberry-orm/data-object/fo_actions-saving-object.ru.md +++ b/pages/products/flexberry-orm/data-object/fo_actions-saving-object.ru.md @@ -14,8 +14,9 @@ lang: ru ```csharp Console.WriteLine("4. How to do something at persistence moment."); -IDataService dataService = DataServiceProvider.DataService; -OrmSample ormSample = new OrmSample(dataService); +IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. +IDataService ds = mainUnityContainer.Resolve(); +OrmSample ormSample = new OrmSample(ds); object primaryKey = ormSample.GetSomeObjectPrimaryKey(typeof(CDDA)); // Как сделать что-то в момент сохранения: @@ -28,10 +29,10 @@ cdda.SetExistObjectPrimaryKey(primaryKey); Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); - -dataService.LoadObject(CDDA.Views.CDDA_E, cdda); + +ds.LoadObject(CDDA.Views.CDDA_E, cdda); cdda.Name = "Huh! " + DateTime.Now; -dataService.UpdateObject(cdda); +ds.UpdateObject(cdda); stopwatch.Stop(); Console.WriteLine("Time taken for loading and persistence: {0} ms.", stopwatch.ElapsedMilliseconds); ``` diff --git a/pages/products/flexberry-orm/data-object/fo_create-multiple-details.ru.md b/pages/products/flexberry-orm/data-object/fo_create-multiple-details.ru.md index 77203e230..bbe7b7066 100644 --- a/pages/products/flexberry-orm/data-object/fo_create-multiple-details.ru.md +++ b/pages/products/flexberry-orm/data-object/fo_create-multiple-details.ru.md @@ -1,71 +1,73 @@ ---- -title: Пример загрузки графа объектов -sidebar: flexberry-orm_sidebar -keywords: Объекты данных, Flexberry ORM, пример, детейл -summsry: Особенности генерации мультидетейлов -toc: true -permalink: ru/fo_create-multiple-details.html -lang: ru ---- - -Полный список примеров кода [Flexberry ORM](fo_flexberry-orm.html) находится в статье ["Примеры кода"](fo_code-samples.html). - -## Создание и сохранение объекта с большим количеством детейлов - -Данный тест осуществляет генерацию большого графа объектов с [детейловыми связями](fo_detail-associations-properties.html) и его сохранение в БД. -Используемая [диаграмма классов](fd_class-diagram.html) имеет вид: - -![](/images/pages/products/flexberry-orm/data-object/details.png) - -При этом все классы [наследуются](fd_inheritance.html) от нехранимого абстрактного класса `D`. -Для каждого массива детейлов каждого объекта генерируется по 10 детейлов, затем все это сохраняется в БД путем передачи [сервису данных](fo_data-service.html) корневого объекта графа. - -```csharp -Console.WriteLine("5. Create a dataobject with multiple details."); - -// Создаем объект данных, у которого несколько детейловых свойств. -D0 aggregator = new D0(); - -// Вызываем метод генерации детейловых объектов. Код метода приведен ниже. -// Иерархия детейлов устроена таким образом, что при задании количества детейлов 10 для каждого объекта -// общее число объектов данных будет превышать 30000. -OrmSample ormSample = new OrmSample(); -ormSample.GenDetails(aggregator, 10); - -Stopwatch stopwatch = new Stopwatch(); -stopwatch.Start(); - -// Объекты будут сохранены в порядке, соответствующем связям между ними (от корня до кончиков). -DataServiceProvider.DataService.UpdateObject(aggregator); - -stopwatch.Stop(); -Console.WriteLine("Time taken for persistence: {0} ms.", stopwatch.ElapsedMilliseconds); -``` - -Метод `GetDetails`: - -```csharp -internal void GenDetails(D dobj, int qtyInEach) -{ - RandomStringGenerator rsg = new RandomStringGenerator(); - dobj.Name = rsg.Generate(200); - dobj.S1 = rsg.Generate(200); - dobj.S2 = rsg.Generate(200); - dobj.S3 = rsg.Generate(200); - dobj.S4 = rsg.Generate(200); - dobj.S5 = rsg.Generate(200); - - string[] detprops = Information.GetPropertyNamesByType(dobj.GetType(), typeof(DetailArray)); - for (int i = 0; i < detprops.Length; i++) - { - DetailArray detarr = (DetailArray)Information.GetPropValueByName(dobj, detprops[i]); - Type dettypetocreate = Information.GetCompatibleTypesForDetailProperty(dobj.GetType(), detprops[i])[0]; - for (int j = 0; j < qtyInEach; j++) - { - D newobj = (D)Activator.CreateInstance(dettypetocreate); - GenDetails(newobj, qtyInEach); - detarr.AddObject(newobj); - } - } -} -``` +--- +title: Пример загрузки графа объектов +sidebar: flexberry-orm_sidebar +keywords: Объекты данных, Flexberry ORM, пример, детейл +summsry: Особенности генерации мультидетейлов +toc: true +permalink: ru/fo_create-multiple-details.html +lang: ru +--- + +Полный список примеров кода [Flexberry ORM](fo_flexberry-orm.html) находится в статье ["Примеры кода"](fo_code-samples.html). + +## Создание и сохранение объекта с большим количеством детейлов + +Данный тест осуществляет генерацию большого графа объектов с [детейловыми связями](fo_detail-associations-properties.html) и его сохранение в БД. +Используемая [диаграмма классов](fd_class-diagram.html) имеет вид: + +![details](/images/pages/products/flexberry-orm/data-object/details.png) + +При этом все классы [наследуются](fd_inheritance.html) от нехранимого абстрактного класса `D`. +Для каждого массива детейлов каждого объекта генерируется по 10 детейлов, затем все это сохраняется в БД путем передачи [сервису данных](fo_data-service.html) корневого объекта графа. + +```csharp +Console.WriteLine("5. Create a dataobject with multiple details."); + +// Создаем объект данных, у которого несколько детейловых свойств. +D0 aggregator = new D0(); + +// Вызываем метод генерации детейловых объектов. Код метода приведен ниже. +// Иерархия детейлов устроена таким образом, что при задании количества детейлов 10 для каждого объекта +// общее число объектов данных будет превышать 30000. +OrmSample ormSample = new OrmSample(); +ormSample.GenDetails(aggregator, 10); + +Stopwatch stopwatch = new Stopwatch(); +stopwatch.Start(); + +// Объекты будут сохранены в порядке, соответствующем связям между ними (от корня до кончиков). +IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. +IDataService ds = mainUnityContainer.Resolve(); +ds.UpdateObject(aggregator); + +stopwatch.Stop(); +Console.WriteLine("Time taken for persistence: {0} ms.", stopwatch.ElapsedMilliseconds); +``` + +Метод `GetDetails`: + +```csharp +internal void GenDetails(D dobj, int qtyInEach) +{ + RandomStringGenerator rsg = new RandomStringGenerator(); + dobj.Name = rsg.Generate(200); + dobj.S1 = rsg.Generate(200); + dobj.S2 = rsg.Generate(200); + dobj.S3 = rsg.Generate(200); + dobj.S4 = rsg.Generate(200); + dobj.S5 = rsg.Generate(200); + + string[] detprops = Information.GetPropertyNamesByType(dobj.GetType(), typeof(DetailArray)); + for (int i = 0; i < detprops.Length; i++) + { + DetailArray detarr = (DetailArray)Information.GetPropValueByName(dobj, detprops[i]); + Type dettypetocreate = Information.GetCompatibleTypesForDetailProperty(dobj.GetType(), detprops[i])[0]; + for (int j = 0; j < qtyInEach; j++) + { + D newobj = (D)Activator.CreateInstance(dettypetocreate); + GenDetails(newobj, qtyInEach); + detarr.AddObject(newobj); + } + } +} +``` diff --git a/pages/products/flexberry-orm/data-object/fo_features-dafault-value.ru.md b/pages/products/flexberry-orm/data-object/fo_features-dafault-value.ru.md index fdabbd1ed..b2039b0c9 100644 --- a/pages/products/flexberry-orm/data-object/fo_features-dafault-value.ru.md +++ b/pages/products/flexberry-orm/data-object/fo_features-dafault-value.ru.md @@ -16,7 +16,7 @@ lang: ru Чтобы указать на [диаграмме классов](fd_class-diagram.html) значение по умолчанию для полей скалярных типов достаточно определить его в [DefaultValue](fo_attributes-class-data.html) у соответствующего поля (обратите внимание на особенности генерации для [DefaultValue](fo_attributes-class-data.html)). -{% include note.html content="Если тип значения по умолчанию не будет соответствовать типу поля, то проект будет сгенерирован, но не скомпилируется." %} +> Если тип значения по умолчанию не будет соответствовать типу поля, то проект будет сгенерирован, но не скомпилируется. ### Cкалярные nullable-типы @@ -27,7 +27,8 @@ Generic Nullable-типы могут быть инициализированы ```cs private System.Nullable fRelease = System.DateTime.Now; ``` -{% include note.html content="Обратите внимание, что задать по умолчанию `null` не получится." %} + +> Обратите внимание, что задать по умолчанию `null` не получится. ### Комплексные типы @@ -35,7 +36,7 @@ private System.Nullable fRelease = System.DateTime.Now; ### Синонимы типов -Для [синонимов типов](fd_typedef.html) задание значения по умолчанию на диаграмме классов происходит аналогично тому, как это происходит у типов, синонимами которых они являются. +Для [синонимов типов](fd_typedef.html) задание значения по умолчанию на диаграмме классов происходит аналогично тому, как это происходит у типов, синонимами которых они являются. ## Задание значения по умолчанию в программном коде @@ -50,12 +51,12 @@ private System.Nullable fRelease = System.DateTime.Now; ```csharp public class WinformC__ПациентE : ICSSoft.STORMNET.UI.BaseWinEdit, IIS.BSTest.DPDIC__ПациентE { - private void WinformC__ПациентE_DataObjectOnFormLoaded(object sender, EventArgs e) - { - ((Пациент) this.DataObject).ФИО = "ФИОПациента"; //задаём значения по умолчанию - ... - } - //... + private void WinformC__ПациентE_DataObjectOnFormLoaded(object sender, EventArgs e) + { + ((Пациент) this.DataObject).ФИО = "ФИОПациента"; //задаём значения по умолчанию + ... + } + //... } ``` @@ -64,41 +65,44 @@ public class WinformC__ПациентE : ICSSoft.STORMNET.UI.BaseWinEdit, IIS.BS ```csharp public class Пациент : ICSSoft.STORMNET.DataObject { - private fФИО = "ФИОПациента"; //установка значения по умолчанию - public string ФИО - { - get - { - return fФИО; - } - - set - { - fФИО = value; - } - } - //... + private fФИО = "ФИОПациента"; //установка значения по умолчанию + public string ФИО + { + get + { + return fФИО; + } + + set + { + fФИО = value; + } + } +//... } ``` ### Задание значения по умолчанию в бизнес-сервере + Код формы: ```csharp public class WinformC__ЗаписьНаПриёмE : ICSSoft.STORMNET.UI.BaseWinEdit, IIS.BSTest.DPDIC__ЗаписьНаПриёмE { - private void WinformC__ЗаписьНаПриёмE_DataObjectOnFormLoaded(object sender, EventArgs e) - { - //определяем, какие бизнес-сервера определены для объекта типа "ЗаписьНаПриём" - BusinessServer[] businessServers = BusinessServerProvider.GetBusinessServer(typeof(ЗаписьНаПриём), DataServiceObjectEvents.OnAllEvents, DataServiceProvider.DataService); - if (businessServers.Length>0) - { - TestBS curBS = (TestBS) businessServers[0]; //берём первый и единственный (в данном случае единственный) - curBS.InitializeRecord(this.DataObject as ЗаписьНаПриём); //задаём значения по умолчанию - EditManager.Change(); //применяем внесённые изменения - } - } - //... + private void WinformC__ЗаписьНаПриёмE_DataObjectOnFormLoaded(object sender, EventArgs e) + { + //определяем, какие бизнес-сервера определены для объекта типа "ЗаписьНаПриём" + IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. + IDataService ds = mainUnityContainer.Resolve(); + BusinessServer[] businessServers = BusinessServerProvider.GetBusinessServer(typeof(ЗаписьНаПриём), DataServiceObjectEvents.OnAllEvents, ds); + if (businessServers.Length>0) + { + TestBS curBS = (TestBS) businessServers[0]; //берём первый и единственный (в данном случае единственный) + curBS.InitializeRecord(this.DataObject as ЗаписьНаПриём); //задаём значения по умолчанию + EditManager.Change(); //применяем внесённые изменения + } + } +//... } ``` @@ -107,10 +111,10 @@ public class WinformC__ЗаписьНаПриёмE : ICSSoft.STORMNET.UI.BaseWin ```csharp public class TestBS : ICSSoft.STORMNET.Business.BusinessServer { - public void InitializeRecord(IIS.BSTest.ЗаписьНаПриём RecordToInitialize) - { - RecordToInitialize.Дата = new DateTime(2012,12,12); //установка значения по умолчанию - } - //... + public void InitializeRecord(IIS.BSTest.ЗаписьНаПриём RecordToInitialize) + { + RecordToInitialize.Дата = new DateTime(2012,12,12); //установка значения по умолчанию + } + //... } ``` diff --git a/pages/products/flexberry-orm/data-object/fo_load-alter-objects.ru.md b/pages/products/flexberry-orm/data-object/fo_load-alter-objects.ru.md index 855280534..0087e63e9 100644 --- a/pages/products/flexberry-orm/data-object/fo_load-alter-objects.ru.md +++ b/pages/products/flexberry-orm/data-object/fo_load-alter-objects.ru.md @@ -1,51 +1,52 @@ ---- -title: Пример загрузки и изменения объекта -sidebar: flexberry-orm_sidebar -keywords: Flexberry ORM, объекты данных, пример -summary: Пример загрузки объекта данных по представлению, его изменения и сохранения -toc: true -permalink: ru/fo_load-alter-objects.html -lang: ru ---- - -В данном примере выполняются следующие действия: - -* Берется [первичный ключ](fo_primary-keys-objects.html) какого-либо из имеющихся в БД объектов класса `CDDA`. -* Создается новый экземпляр класса `CDDA`, ему присваивается этот [первичный ключ](fo_primary-keys-objects.html). -* Производится загрузка свойств этого экземпляра посредством [сервиса данных](fo_data-service.html). Значения загружаются из записи, соответствующей установленному [первичному ключу](fo_primary-keys-objects.html). - При загрузке применяется [представление](fd_view-definition.html). -* Выполняется изменение свойств и сохранение объекта. - -```csharp -Console.WriteLine("2. How to load dataobject in specific view, change it\'s property, then persist. Object status and loading state."); - -IDataService dataService = DataServiceProvider.DataService; - -// Инициализация вспомогательного объекта, с помощью которого мы получим первичный ключ произвольного объекта -// заданного типа. -OrmSample ormSample = new OrmSample(dataService); -object primaryKey = ormSample.GetSomeObjectPrimaryKey(typeof(CDDA)); - -// Для загрузки объекта данных необходимо создать новый экземпляр объекта данных, присвоить ему имеющийся первичный ключ, а затем -// передать его в метод LoadObject сервиса данных. При этом запись с таким первичным ключом должна существовать в БД. -CDDA cdda = new CDDA(); -cdda.SetExistObjectPrimaryKey(primaryKey); - -// Кроме самого экземпляра, свойства которого необходимо загрузить, в метод LoadObject переадается представление. -// Представление - это набор свойств объекта. Представления можно создать в Flexberry, либо с помощью атрибута ViewAttribute. -// В данном случае представление определяет, какие свойства будут загружены. -dataService.LoadObject(CDDA.Views.CDDA_E, cdda); - -// После загрузки статус объекта (cdda.GetStatus()) равен ObjectStatus.UnAltered. После вызова следующей строки он изменится на ObjectStatus.Altered. -// Изменять можно только загруженные свойства. Иначе при сохранении объекта получим ошибку. -cdda.Name = "Blablabla " + DateTime.Now; - -Stopwatch stopwatch = new Stopwatch(); -stopwatch.Start(); - -// Сохранение объекта. Обновляются только загруженные свойства. -dataService.UpdateObject(cdda); - -stopwatch.Stop(); -Console.WriteLine("Time taken for persistence: {0} ms.", stopwatch.ElapsedMilliseconds); -``` +--- +title: Пример загрузки и изменения объекта +sidebar: flexberry-orm_sidebar +keywords: Flexberry ORM, объекты данных, пример +summary: Пример загрузки объекта данных по представлению, его изменения и сохранения +toc: true +permalink: ru/fo_load-alter-objects.html +lang: ru +--- + +В данном примере выполняются следующие действия: + +* Берется [первичный ключ](fo_primary-keys-objects.html) какого-либо из имеющихся в БД объектов класса `CDDA`. +* Создается новый экземпляр класса `CDDA`, ему присваивается этот [первичный ключ](fo_primary-keys-objects.html). +* Производится загрузка свойств этого экземпляра посредством [сервиса данных](fo_data-service.html). Значения загружаются из записи, соответствующей установленному [первичному ключу](fo_primary-keys-objects.html). + При загрузке применяется [представление](fd_view-definition.html). +* Выполняется изменение свойств и сохранение объекта. + +```csharp +Console.WriteLine("2. How to load dataobject in specific view, change it\'s property, then persist. Object status and loading state."); + +IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. +IDataService ds = mainUnityContainer.Resolve(); + +// Инициализация вспомогательного объекта, с помощью которого мы получим первичный ключ произвольного объекта +// заданного типа. +OrmSample ormSample = new OrmSample(dataService); +object primaryKey = ormSample.GetSomeObjectPrimaryKey(typeof(CDDA)); + +// Для загрузки объекта данных необходимо создать новый экземпляр объекта данных, присвоить ему имеющийся первичный ключ, а затем +// передать его в метод LoadObject сервиса данных. При этом запись с таким первичным ключом должна существовать в БД. +CDDA cdda = new CDDA(); +cdda.SetExistObjectPrimaryKey(primaryKey); + +// Кроме самого экземпляра, свойства которого необходимо загрузить, в метод LoadObject переадается представление. +// Представление - это набор свойств объекта. Представления можно создать в Flexberry, либо с помощью атрибута ViewAttribute. +// В данном случае представление определяет, какие свойства будут загружены. +dataService.LoadObject(CDDA.Views.CDDA_E, cdda); + +// После загрузки статус объекта (cdda.GetStatus()) равен ObjectStatus.UnAltered. После вызова следующей строки он изменится на ObjectStatus.Altered. +// Изменять можно только загруженные свойства. Иначе при сохранении объекта получим ошибку. +cdda.Name = "Blablabla " + DateTime.Now; + +Stopwatch stopwatch = new Stopwatch(); +stopwatch.Start(); + +// Сохранение объекта. Обновляются только загруженные свойства. +dataService.UpdateObject(cdda); + +stopwatch.Stop(); +Console.WriteLine("Time taken for persistence: {0} ms.", stopwatch.ElapsedMilliseconds); +``` diff --git a/pages/products/flexberry-orm/data-object/fo_load-multiple-details-example.ru.md b/pages/products/flexberry-orm/data-object/fo_load-multiple-details-example.ru.md index 5af626f2b..dfc9bd016 100644 --- a/pages/products/flexberry-orm/data-object/fo_load-multiple-details-example.ru.md +++ b/pages/products/flexberry-orm/data-object/fo_load-multiple-details-example.ru.md @@ -1,56 +1,57 @@ ---- -title: Пример загрузки графа объектов -sidebar: flexberry-orm_sidebar -keywords: Flexberry ORM, объекты данных, пример -summary: Особенности загрузки объекта данных с большим количеством детейлов -toc: true -permalink: ru/fo_load-multiple-details-example.html -lang: ru ---- - -Здесь производится загрузка всех объектов, созданных в [примере](fo_actions-saving-object.html). - -```csharp -Console.WriteLine("6. Loading a dataobject with multiple details."); - -IDataService dataService = DataServiceProvider.DataService; -OrmSample ormSample = new OrmSample(dataService); -object primaryKey = ormSample.GetSomeObjectPrimaryKey(typeof(D0)); - -D0 aggregator = new D0(); -aggregator.SetExistObjectPrimaryKey(primaryKey); - -// Чтобы ускорить загрузку, можно раскомментировать эту строку. -// aggregator.DisableInitDataCopy(); -Stopwatch stopwatch = new Stopwatch(); -stopwatch.Start(); - -dataService.LoadObject(D0.Views.FULLD0_E, aggregator); -stopwatch.Stop(); -Console.WriteLine("Time taken for loading: {0} ms.", stopwatch.ElapsedMilliseconds); - -// Убедимся, что в каждом объекте, в каждом детейловом свойстве содержится 10 детейлов, которые были сохранены туда. -ormSample.CheckDetailsQty(aggregator, 10); -Console.WriteLine("CheckDetailsQty: OK."); -``` - -Код метода `CheckDetailsQty`: - -```csharp -internal void CheckDetailsQty(D dobj, int qtyInEach) -{ - string[] detprops = Information.GetPropertyNamesByType(dobj.GetType(), typeof(DetailArray)); - for (int i = 0; i < detprops.Length; i++) - { - DetailArray detarr = (DetailArray)Information.GetPropValueByName(dobj, detprops[i]); - if (detarr.Count != qtyInEach) - throw new Exception(string.Format("Missing reading of {0}!", detprops[i])); - - for (int j = 0; j < detarr.Count; j++) - { - D obj = (D)detarr.ItemByIndex(j); - CheckDetailsQty(obj, qtyInEach); - } - } -} -``` +--- +title: Пример загрузки графа объектов +sidebar: flexberry-orm_sidebar +keywords: Flexberry ORM, объекты данных, пример +summary: Особенности загрузки объекта данных с большим количеством детейлов +toc: true +permalink: ru/fo_load-multiple-details-example.html +lang: ru +--- + +Здесь производится загрузка всех объектов, созданных в [примере](fo_actions-saving-object.html). + +```csharp +Console.WriteLine("6. Loading a dataobject with multiple details."); + +IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. +IDataService ds = mainUnityContainer.Resolve(); +OrmSample ormSample = new OrmSample(dataService); +object primaryKey = ormSample.GetSomeObjectPrimaryKey(typeof(D0)); + +D0 aggregator = new D0(); +aggregator.SetExistObjectPrimaryKey(primaryKey); + +// Чтобы ускорить загрузку, можно раскомментировать эту строку. +// aggregator.DisableInitDataCopy(); +Stopwatch stopwatch = new Stopwatch(); +stopwatch.Start(); + +dataService.LoadObject(D0.Views.FULLD0_E, aggregator); +stopwatch.Stop(); +Console.WriteLine("Time taken for loading: {0} ms.", stopwatch.ElapsedMilliseconds); + +// Убедимся, что в каждом объекте, в каждом детейловом свойстве содержится 10 детейлов, которые были сохранены туда. +ormSample.CheckDetailsQty(aggregator, 10); +Console.WriteLine("CheckDetailsQty: OK."); +``` + +Код метода `CheckDetailsQty`: + +```csharp +internal void CheckDetailsQty(D dobj, int qtyInEach) +{ + string[] detprops = Information.GetPropertyNamesByType(dobj.GetType(), typeof(DetailArray)); + for (int i = 0; i < detprops.Length; i++) + { + DetailArray detarr = (DetailArray)Information.GetPropValueByName(dobj, detprops[i]); + if (detarr.Count != qtyInEach) + throw new Exception(string.Format("Missing reading of {0}!", detprops[i])); + + for (int j = 0; j < detarr.Count; j++) + { + D obj = (D)detarr.ItemByIndex(j); + CheckDetailsQty(obj, qtyInEach); + } + } +} +``` diff --git a/pages/products/flexberry-orm/data-object/fo_prototyping-example.ru.md b/pages/products/flexberry-orm/data-object/fo_prototyping-example.ru.md index 3ea261048..b884f0f2a 100644 --- a/pages/products/flexberry-orm/data-object/fo_prototyping-example.ru.md +++ b/pages/products/flexberry-orm/data-object/fo_prototyping-example.ru.md @@ -1,72 +1,73 @@ ---- -title: Пример прототипизации объекта -sidebar: flexberry-orm_sidebar -keywords: Объекты данных, Flexberry ORM, пример -summary: Пример создания копии объекта данных -toc: true -permalink: ru/fo_prototyping-example.html -lang: ru ---- - -Полный список примеров кода [Flexberry ORM](fo_flexberry-orm.html) находится в статье ["Примеры кода"](fo_code-samples.html). - -## Пример создания копии объекта данных - -```csharp -Console.WriteLine("7. Prototyping."); -IDataService dataService = DataServiceProvider.DataService; -OrmSample ormSample = new OrmSample(dataService); -object primaryKey = ormSample.GetSomeObjectPrimaryKey(typeof(D0)); - -D0 aggregator = new D0(); -aggregator.SetExistObjectPrimaryKey(primaryKey); - -Stopwatch stopwatch = new Stopwatch(); -stopwatch.Start(); - -dataService.LoadObject(D0.Views.D0_E, aggregator); - -stopwatch.Stop(); -long loadObjectTime = stopwatch.ElapsedMilliseconds; -stopwatch.Restart(); - -// Этот метод делает каждый объект в иерархии новым (листинг приведен ниже). -aggregator.Prototype(true); - -stopwatch.Stop(); -long prototypingTime = stopwatch.ElapsedMilliseconds; -stopwatch.Restart(); - -dataService.UpdateObject(aggregator); - -stopwatch.Stop(); -long updateTime = stopwatch.ElapsedMilliseconds; - -Console.WriteLine("Time taken for loading: {1} ms{0}prototyping: {2} ms{0}persistence: {3} ms.", Environment.NewLine, loadObjectTime, prototypingTime, updateTime); -``` - -Код метода `Prototype`: - -```csharp -public virtual void Prototype(bool withDetails) -{ - KeyGenerator.Generate(this, null); - this.SetStatus(ObjectStatus.Created); - this.SetLoadingState(LoadingState.NotLoaded); - this.SetLoadedProperties(new string[0]); - InitDataCopy(); - if (withDetails) - { - string[] properties = Information.GetAllPropertyNames(GetType()); - foreach (string property in properties) - { - Type proptype = Information.GetPropertyType(GetType(), property); - if (proptype.IsSubclassOf(typeof(DetailArray))) - { - foreach (D detobj in (DetailArray)Information.GetPropValueByName(this, property)) - detobj.Prototype(withDetails); - } - } - } -} -``` \ No newline at end of file +--- +title: Пример прототипизации объекта +sidebar: flexberry-orm_sidebar +keywords: Объекты данных, Flexberry ORM, пример +summary: Пример создания копии объекта данных +toc: true +permalink: ru/fo_prototyping-example.html +lang: ru +--- + +Полный список примеров кода [Flexberry ORM](fo_flexberry-orm.html) находится в статье ["Примеры кода"](fo_code-samples.html). + +## Пример создания копии объекта данных + +```csharp +Console.WriteLine("7. Prototyping."); +IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. +IDataService ds = mainUnityContainer.Resolve(); +OrmSample ormSample = new OrmSample(dataService); +object primaryKey = ormSample.GetSomeObjectPrimaryKey(typeof(D0)); + +D0 aggregator = new D0(); +aggregator.SetExistObjectPrimaryKey(primaryKey); + +Stopwatch stopwatch = new Stopwatch(); +stopwatch.Start(); + +dataService.LoadObject(D0.Views.D0_E, aggregator); + +stopwatch.Stop(); +long loadObjectTime = stopwatch.ElapsedMilliseconds; +stopwatch.Restart(); + +// Этот метод делает каждый объект в иерархии новым (листинг приведен ниже). +aggregator.Prototype(true); + +stopwatch.Stop(); +long prototypingTime = stopwatch.ElapsedMilliseconds; +stopwatch.Restart(); + +dataService.UpdateObject(aggregator); + +stopwatch.Stop(); +long updateTime = stopwatch.ElapsedMilliseconds; + +Console.WriteLine("Time taken for loading: {1} ms{0}prototyping: {2} ms{0}persistence: {3} ms.", Environment.NewLine, loadObjectTime, prototypingTime, updateTime); +``` + +Код метода `Prototype`: + +```csharp +public virtual void Prototype(bool withDetails) +{ + KeyGenerator.Generate(this, null); + this.SetStatus(ObjectStatus.Created); + this.SetLoadingState(LoadingState.NotLoaded); + this.SetLoadedProperties(new string[0]); + InitDataCopy(); + if (withDetails) + { + string[] properties = Information.GetAllPropertyNames(GetType()); + foreach (string property in properties) + { + Type proptype = Information.GetPropertyType(GetType(), property); + if (proptype.IsSubclassOf(typeof(DetailArray))) + { + foreach (D detobj in (DetailArray)Information.GetPropValueByName(this, property)) + detobj.Prototype(withDetails); + } + } + } +} +``` diff --git a/pages/products/flexberry-orm/data-service/fo_Intercept-formation-sql-query.ru.md b/pages/products/flexberry-orm/data-service/fo_Intercept-formation-sql-query.ru.md index eeaea4792..ab9d6cbd2 100644 --- a/pages/products/flexberry-orm/data-service/fo_Intercept-formation-sql-query.ru.md +++ b/pages/products/flexberry-orm/data-service/fo_Intercept-formation-sql-query.ru.md @@ -1,63 +1,65 @@ ---- -title: Перехват формирования SQL-запроса к БД -sidebar: flexberry-orm_sidebar -keywords: Flexberry ORM, база данных, сервис данных, пример -summary: Примеры перехватов формирования SQL-запросов -toc: true -permalink: ru/fo_intercept-formation-sql-query.html -lang: ru ---- - -[SQLDataService](fo_sql-data-service.html) позволяет осуществлять перехват формирования SQL-запроса к БД за счёт применения [делегатов OnGenerateSQLSelect, AfterGenerateSQLSelectQuery, OnCreateCommand](fo_sql-data-service.html). - -`Примеры перехватов формирования SQL-запросов`: - -``` csharp -static void Main() -{ - //... - // создаем датасервис - ICSSoft.STORMNET.Business.SQLDataService ds = (ICSSoft.STORMNET.Business.SQLDataService)ICSSoft.STORMNET.Business.DataServiceProvider.DataService; - // перед формированием - ds.OnGenerateSQLSelect+=new ICSSoft.STORMNET.Business.OnGenerateSQLSelectEventHandler(ds_OnGenerateSQLSelect); - // после формирования - ds.AfterGenerateSQLSelectQuery+=new ICSSoft.STORMNET.Business.AfterGenerateSQLSelectQueryEventHandler(ds_AfterGenerateSQLSelectQuery); - // строка посылается на выполение ... - ds.OnCreateCommand+=new ICSSoft.STORMNET.Business.OnCreateCommandEventHandler(ds_OnCreateCommand); - //... -} -public static void ds_OnGenerateSQLSelect(object sender, ICSSoft.STORMNET.Business.GenerateSQLSelectQueryEventArgs e) -{ - //... - if (e.CustomizationStruct.View == null) return; - //для Словарей ограничим общеупотребительными значениями... - if(e.CustomizationStruct.View.Name == "СловарьL") - { - e.CustomizationStruct.LimitFunction = AddОбщУпотр(e.CustomizationStruct.LimitFunction); - } - //... -} - -public static void ds_AfterGenerateSQLSelectQuery(object sender, ICSSoft.STORMNET.Business.GenerateSQLSelectQueryEventArgs e) -{ - //... - //для View ПеремИАрхив... - if (e.CustomizationStruct.View.Name == "ПеремИАрхив") - { - e.GeneratedQuery = System.Text.RegularExpressions.Regex.Replace(e.GeneratedQuery.ToUpper(), - "^SELECT","SELECT TOP 100"); - } - //... -} - -private void ds_OnCreateCommand(object sender, CreateCommandEventArgs e) -{ - //... - //Для строки удаления Проживаний - if (e.Command.CommandText.StartsWith("DELETE FROM \"Проживание\"")) - { - //... - } - //... -} -``` +--- +title: Перехват формирования SQL-запроса к БД +sidebar: flexberry-orm_sidebar +keywords: Flexberry ORM, база данных, сервис данных, пример +summary: Примеры перехватов формирования SQL-запросов +toc: true +permalink: ru/fo_intercept-formation-sql-query.html +lang: ru +--- + +[SQLDataService](fo_sql-data-service.html) позволяет осуществлять перехват формирования SQL-запроса к БД за счёт применения [делегатов OnGenerateSQLSelect, AfterGenerateSQLSelectQuery, OnCreateCommand](fo_sql-data-service.html). + +`Примеры перехватов формирования SQL-запросов`: + +``` csharp +static void Main() +{ + //... + // создаем датасервис + IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. + IDataService ds = mainUnityContainer.Resolve(); + ICSSoft.STORMNET.Business.SQLDataService sqldataservice = (ICSSoft.STORMNET.Business.SQLDataService)ds; + // перед формированием + sqldataservice.OnGenerateSQLSelect+=new ICSSoft.STORMNET.Business.OnGenerateSQLSelectEventHandler(ds_OnGenerateSQLSelect); + // после формирования + sqldataservice.AfterGenerateSQLSelectQuery+=new ICSSoft.STORMNET.Business.AfterGenerateSQLSelectQueryEventHandler(ds_AfterGenerateSQLSelectQuery); + // строка посылается на выполение ... + sqldataservice.OnCreateCommand+=new ICSSoft.STORMNET.Business.OnCreateCommandEventHandler(ds_OnCreateCommand); + //... +} +public static void ds_OnGenerateSQLSelect(object sender, ICSSoft.STORMNET.Business.GenerateSQLSelectQueryEventArgs e) +{ + //... + if (e.CustomizationStruct.View == null) return; + //для Словарей ограничим общеупотребительными значениями... + if(e.CustomizationStruct.View.Name == "СловарьL") + { + e.CustomizationStruct.LimitFunction = AddОбщУпотр(e.CustomizationStruct.LimitFunction); + } + //... +} + +public static void ds_AfterGenerateSQLSelectQuery(object sender, ICSSoft.STORMNET.Business.GenerateSQLSelectQueryEventArgs e) +{ + //... + //для View ПеремИАрхив... + if (e.CustomizationStruct.View.Name == "ПеремИАрхив") + { + e.GeneratedQuery = System.Text.RegularExpressions.Regex.Replace(e.GeneratedQuery.ToUpper(), + "^SELECT","SELECT TOP 100"); + } + //... +} + +private void ds_OnCreateCommand(object sender, CreateCommandEventArgs e) +{ + //... + //Для строки удаления Проживаний + if (e.Command.CommandText.StartsWith("DELETE FROM \"Проживание\"")) + { + //... + } + //... +} +``` diff --git a/pages/products/flexberry-orm/data-service/fo_construction-ds.ru.md b/pages/products/flexberry-orm/data-service/fo_construction-ds.ru.md index 27238ba1e..d043e8fe3 100644 --- a/pages/products/flexberry-orm/data-service/fo_construction-ds.ru.md +++ b/pages/products/flexberry-orm/data-service/fo_construction-ds.ru.md @@ -1,26 +1,27 @@ ---- -title: Конструирование сервиса данных -sidebar: flexberry-orm_sidebar -keywords: Flexberry ORM, сервис данных -summary: Способы создания сервиса данных в приложении -toc: true -permalink: ru/fo_construction-ds.html -lang: ru ---- - -Создать [сервис данных](fo_data-service.html) можно разными способами: - -1.Сконструировать [сервис данных](fo_data-service.html) - -```csharp -IDataService ds = new ODBCDataService(); -ds.CustomizationString="DSN=LibNetSample"; -``` - -2.В WinForms-приложениях можно «бросить» [сервис данных](fo_data-service.html) на форму как контрол, затем настроить его через стандартное окно редактирования свойств в среде Visual Studio. - -3.[Получить его у провайдера сервиса данных](fo_ds-provider.html). - -```csharp -IDataService ds = DataServiceProvider.DataService; -``` +--- +title: Конструирование сервиса данных +sidebar: flexberry-orm_sidebar +keywords: Flexberry ORM, сервис данных +summary: Способы создания сервиса данных в приложении +toc: true +permalink: ru/fo_construction-ds.html +lang: ru +--- + +Создать [сервис данных](fo_data-service.html) можно разными способами: + +1.Сконструировать [сервис данных](fo_data-service.html) + +```csharp +IDataService ds = new ODBCDataService(); +ds.CustomizationString="DSN=LibNetSample"; +``` + +2.В WinForms-приложениях можно «бросить» [сервис данных](fo_data-service.html) на форму как контрол, затем настроить его через стандартное окно редактирования свойств в среде Visual Studio. + +3.[Получить его у провайдера сервиса данных](fo_ds-provider.html). + +```csharp +IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. +IDataService ds = mainUnityContainer.Resolve(); +``` diff --git a/pages/products/flexberry-orm/data-service/fo_dr-data-service.ru.md b/pages/products/flexberry-orm/data-service/fo_dr-data-service.ru.md index 1cff91d06..d4e1fc9c6 100644 --- a/pages/products/flexberry-orm/data-service/fo_dr-data-service.ru.md +++ b/pages/products/flexberry-orm/data-service/fo_dr-data-service.ru.md @@ -1,44 +1,43 @@ ---- -title: DRDataService -sidebar: flexberry-orm_sidebar -keywords: Flexberry ORM, сервис данных, чтение данных -summary: Использование dirty read -toc: true -permalink: ru/fo_dr-data-service.html -lang: ru ---- - -`DRDataService` - [сервис данных](fo_data-service.html), наследник [SQLDataService](fo_sql-data-service.html), обладает тем же функционалом, что и обычный [MSSQLDataService](fo_mssql-data-service.html), но при чтении данных используется ["грязное чтение (dirty read)"](http://msdn.microsoft.com/ru-ru/library/ms173763.aspx). - -## Получение экземпляра DRDataService - -Экземпляр DRDataService можно получить через [UnityFactory](fo_unity-factory.html), выполнив следующий код: - -```csharp - IUnityContainer container = UnityFactory.CreateContainer(); - IDataService dataService = container.Resolve("DRDataService"); - dataService.CustomizationString = DataServiceProvider.DataService.CustomizationString; -``` - -## Настройка DataService - -Настройка `DRDataService` через конфигурационный файл : - -```xml - - - -
- - - - - - - - - - -``` - -Строка соединения в данном примере настраивается так, как указано в статье про [`DataServiceProvider`](fo_ds-provider.html) +--- +title: DRDataService +sidebar: flexberry-orm_sidebar +keywords: Flexberry ORM, сервис данных, чтение данных +summary: Использование dirty read +toc: true +permalink: ru/fo_dr-data-service.html +lang: ru +--- + +`DRDataService` - [сервис данных](fo_data-service.html), наследник [SQLDataService](fo_sql-data-service.html), обладает тем же функционалом, что и обычный [MSSQLDataService](fo_mssql-data-service.html), но при чтении данных используется ["грязное чтение (dirty read)"](http://msdn.microsoft.com/ru-ru/library/ms173763.aspx). + +## Получение экземпляра DRDataService + +Экземпляр DRDataService можно получить через [UnityFactory](fo_unity-factory.html), выполнив следующий код: + +```csharp +IDataService dataService = container.Resolve("DRDataService"); +// Resolve("DRDataService") приходит со строкой соединения +``` + +## Настройка DataService + +Настройка `DRDataService` через конфигурационный файл : + +```xml + + + +
+ + + + + + + + + + +``` + +Строка соединения в данном примере настраивается так, как указано в статье про [`DataServiceProvider`](fo_ds-provider.html) diff --git a/pages/products/flexberry-orm/data-service/fo_instantiate-persist-objects.ru.md b/pages/products/flexberry-orm/data-service/fo_instantiate-persist-objects.ru.md index 4e3ecb27f..c9d940c69 100644 --- a/pages/products/flexberry-orm/data-service/fo_instantiate-persist-objects.ru.md +++ b/pages/products/flexberry-orm/data-service/fo_instantiate-persist-objects.ru.md @@ -1,101 +1,103 @@ ---- -title: Создание и сохранение объектов данных -sidebar: flexberry-orm_sidebar -keywords: Flexberry ORM, база данных, сервис данных, пример -summary: Пример создания объектов данных и сохранение их в БД -toc: true -permalink: ru/fo_instantiate-persist-objects.html -lang: ru ---- - -В данном примере создается граф объектов данных и затем производится их сохранение в БД с помощью [сервиса данных](fo_data-service.html). - -```csharp -Console.WriteLine("1. How to instantiate dataobjects and persist into DB."); - -// Объекты данных создаются как и экземпляры других классов .Net - с помощью вызова конструктора. -Country country1 = new Country { Name = "Greece" }; -Country country2 = new Country { Name = "USA" }; -Country country3 = new Country { Name = "Ireland" }; - -Person person1 = new Person { LastName = "Johnson", FirstName = "John" }; -Person person2 = new Person { LastName = "McLaren", FirstName = "Alice" }; - -Publisher publisher1 = new Publisher { Name = "First Publisher", Country = country1 }; - -Publisher publisher2 = new Publisher { Name = "Second Publisher", Country = country2 }; - -CDDA cdda = new CDDA -{ - Publisher = publisher1, Name = "Strange music", Price = new Dollar(0, 87) -}; - -// Добавление детейлов в объект данных. -cdda.Track.Add(new Track() -{ - Name = "My strange love", - Author = person1, - Singer = person2, - Length = new Random().Next(100, 600) -}); -cdda.Track.Add(new Track() -{ - Name = "Stupid is as stupid does", - Author = person2, - Singer = person1, - Length = new Random().Next(100, 600) -}); -cdda.Track.Add(new Track() -{ - Name = "Save my life", - Author = person2, - Singer = person1, - Length = new Random().Next(100, 600) -}); - -CDDD cddd = new CDDD(); -cddd.Publisher = publisher2; -cddd.Name = "Old software"; -cddd.Capacity = 640; -cddd.Price = new Dollar(1, 52); - -// Объекты данных, которые нужно сохранить, добавим в список. -List objectsToUpdate = new List(); - -for (int i = 0; i < 5; i++) -{ - DVD dvd = new DVD(); - dvd.Publisher = publisher1; - dvd.Name = string.Format("Movie {0}", i); - dvd.Capacity = i * 100; - dvd.Price = new Dollar(2, 66); - objectsToUpdate.Add(dvd); -} - -// Добавление всех объектов, которые нужно обновить, в список для обновления. -objectsToUpdate.AddRange(new ICSSoft.STORMNET.DataObject[] -{ - country1, country2, country3, person1, person2, publisher1, publisher2, cdda, cddd -}); - -try -{ - ICSSoft.STORMNET.DataObject[] objectsToUpdateArray = objectsToUpdate.ToArray(); - - Stopwatch stopwatch = new Stopwatch(); - stopwatch.Start(); - - // DataServiceProvider.DataService создает сервис данных, тип которого задан в конфигурационном файле (ключи DataServiceType, CustomizationStrings в секции appSettings). - // Flexberry ORM сохраняет объекты данных в соответствии с их состоянием. Зависимости между объектами обрабатываются автоматически. Все запросы выполняются в одной транзакции. - // Таким образом, один вызов UpdateObjects соответствует одной транзакции БД. - // Кроме этого, существует метод UpdateObject для обновления одиночного объекта (и графа объектов данных, на которые он ссылается). - DataServiceProvider.DataService.UpdateObjects(ref objectsToUpdateArray); - - stopwatch.Stop(); - Console.WriteLine("Time taken for persistence: {0} ms.", stopwatch.ElapsedMilliseconds); -} -catch (Exception exc) -{ - Console.WriteLine("Something wrong: {0}", exc); -} -``` +--- +title: Создание и сохранение объектов данных +sidebar: flexberry-orm_sidebar +keywords: Flexberry ORM, база данных, сервис данных, пример +summary: Пример создания объектов данных и сохранение их в БД +toc: true +permalink: ru/fo_instantiate-persist-objects.html +lang: ru +--- + +В данном примере создается граф объектов данных и затем производится их сохранение в БД с помощью [сервиса данных](fo_data-service.html). + +```csharp +Console.WriteLine("1. How to instantiate dataobjects and persist into DB."); + +// Объекты данных создаются как и экземпляры других классов .Net - с помощью вызова конструктора. +Country country1 = new Country { Name = "Greece" }; +Country country2 = new Country { Name = "USA" }; +Country country3 = new Country { Name = "Ireland" }; + +Person person1 = new Person { LastName = "Johnson", FirstName = "John" }; +Person person2 = new Person { LastName = "McLaren", FirstName = "Alice" }; + +Publisher publisher1 = new Publisher { Name = "First Publisher", Country = country1 }; + +Publisher publisher2 = new Publisher { Name = "Second Publisher", Country = country2 }; + +CDDA cdda = new CDDA +{ + Publisher = publisher1, Name = "Strange music", Price = new Dollar(0, 87) +}; + +// Добавление детейлов в объект данных. +cdda.Track.Add(new Track() +{ + Name = "My strange love", + Author = person1, + Singer = person2, + Length = new Random().Next(100, 600) +}); +cdda.Track.Add(new Track() +{ + Name = "Stupid is as stupid does", + Author = person2, + Singer = person1, + Length = new Random().Next(100, 600) +}); +cdda.Track.Add(new Track() +{ + Name = "Save my life", + Author = person2, + Singer = person1, + Length = new Random().Next(100, 600) +}); + +CDDD cddd = new CDDD(); +cddd.Publisher = publisher2; +cddd.Name = "Old software"; +cddd.Capacity = 640; +cddd.Price = new Dollar(1, 52); + +// Объекты данных, которые нужно сохранить, добавим в список. +List objectsToUpdate = new List(); + +for (int i = 0; i < 5; i++) +{ + DVD dvd = new DVD(); + dvd.Publisher = publisher1; + dvd.Name = string.Format("Movie {0}", i); + dvd.Capacity = i * 100; + dvd.Price = new Dollar(2, 66); + objectsToUpdate.Add(dvd); +} + +// Добавление всех объектов, которые нужно обновить, в список для обновления. +objectsToUpdate.AddRange(new ICSSoft.STORMNET.DataObject[] +{ + country1, country2, country3, person1, person2, publisher1, publisher2, cdda, cddd +}); + +try +{ + ICSSoft.STORMNET.DataObject[] objectsToUpdateArray = objectsToUpdate.ToArray(); + + Stopwatch stopwatch = new Stopwatch(); + stopwatch.Start(); + + // IDataService создает сервис данных, тип которого задан в конфигурационном файле (ключи DataServiceType, CustomizationStrings в секции appSettings). + // Flexberry ORM сохраняет объекты данных в соответствии с их состоянием. Зависимости между объектами обрабатываются автоматически. Все запросы выполняются в одной транзакции. + // Таким образом, один вызов UpdateObjects соответствует одной транзакции БД. + // Кроме этого, существует метод UpdateObject для обновления одиночного объекта (и графа объектов данных, на которые он ссылается). + IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. + IDataService ds = mainUnityContainer.Resolve(); + ds.UpdateObjects(ref objectsToUpdateArray); + + stopwatch.Stop(); + Console.WriteLine("Time taken for persistence: {0} ms.", stopwatch.ElapsedMilliseconds); +} +catch (Exception exc) +{ + Console.WriteLine("Something wrong: {0}", exc); +} +``` diff --git a/pages/products/flexberry-orm/data-service/fo_loading-customization-struct.ru.md b/pages/products/flexberry-orm/data-service/fo_loading-customization-struct.ru.md index 71f8635d8..2af91ce09 100644 --- a/pages/products/flexberry-orm/data-service/fo_loading-customization-struct.ru.md +++ b/pages/products/flexberry-orm/data-service/fo_loading-customization-struct.ru.md @@ -1,74 +1,75 @@ ---- -title: Настройка параметров чтения (LCS) -sidebar: flexberry-orm_sidebar -keywords: Flexberry ORM, сервис данных, lcs, ограничение, вычитка, фильтрация, loading -summary: Настройка параметров выборки данных LoadingCustomizationStruct, типы данных, представление, ограничение, постраничная загрузка -toc: true -permalink: ru/fo_loading-customization-struct.html -lang: ru ---- - -`LoadingCustomizationStruct` - это класс Flexberry ORM для задания параметров выборки данных (в т.ч. ограничение), реализующий собственное API, в отличие от альтернативного варианта на основе LINQ. `LoadingCustomizationStruct` позволяет полностью настроить параметры [сервиса данных](fo_construction-ds.html) для операций чтения объектов данных. - -Удобно создавать структуру `LoadingCustomizationStruct` с помощью статического метода `GetSimpleStruct`. - -``` csharp -LoadingCustomizationStruct lcs = LoadingCustomizationStruct.GetSimpleStruct(typeof(Шапка), "ШапкаE"); -``` - -## Параметры `LoadingCustomizationStruct` - -`LoadingCustomizationStruct` позволяет настраивать следующие параметры чтения: - -* `View` — указывает [представление](fd_view-definition.html), в соответствии с которым будет выполнено чтение; -* `ReturnTop` — указание количества возвращаемых записей; -* `LoadingTypes` — указывает классы данных, чьи экземпляры требуется читать ([пример](fo_reading-several-types-objects.html)); -* `ColumnsSort` — параметры сортировки возвращаемых результатов; -* `ColumnsOrder` — порядок следования свойств объекта данных в результирующей строке с разделителями, актуально, если для чтения используется метод [сервиса данных](fo_construction-ds.html) `LoadStringedObjectView`. -* `InitDataCopy` — включение или отключение инициализации [копии данных](fo_data-object-copy.html) при вычитке данных. -* `LimitFunction` — [ограничение на зачитываемые объекты данных](fo_limit-function.html), с сервера будут возвращены только те объекты, что удовлетворяют данному ограничению; -* `Distinct` — получение различных данных (используется, например, с методом [LoadRawValues SQLDataService](fo_standard-data-services.html)). -* `LoadingBufferSize` — размер порции при [порционном чтении](fo_reading-portion.html); -* `RowNumber` — указание диапазона индексов загружаемых объектов, `lcs.RowNumber = new RowNumberDef(2, 5);` (удобно, например, для постраничного вывода). - -{% include note.html content="__Представление и ограничение:__ Представление `View` должно содержать в себе все свойства, которые используются в ограничении `LimitFunction`, чтобы не произошло ошибки или неверного счёта. Если есть потребность расширить [представление](fd_view-definition.html) в соответствии с функцией ограничения `LimitFunction`, можно воспользоваться специальным классом [ViewPropertyAppender](fo_view-property-appender.html)." %} - -## Применение `LoadingCustomizationStruct` - -Чтобы вычитать набор данных из базы в память, необходимо - -1. Создать объект типа ICSSoft.STORMNET.Business.LoadingCustomizationStruct - -``` csharp -LoadingCustomizationStruct lcs = LoadingCustomizationStruct.GetSimpleStruct(тип, представление); - -``` -2. возможно вручную установить [представление](fd_view-definition.html) - -``` csharp -lcs.View = Клиент.Views.КлиентE; -``` - -3. Установить тип вычитываемых объектов - -``` csharp -lcs.LoadingTypes=new Type[) {typeof(Кредит)}; -``` - -4. Наложить [ограничение](fo_limit-function.html) на вычитываемые объекты (если ограничение не будет наложено - вычитаются все объекты такого типа) - -``` csharp -lcs.LimitFunction = <Объект типа ICSSoft.STORMNET.FunctionalLanguage.Function> -``` - -5. Настроить другие параметры чтения (не обязательно) -6. Сделать запрос к серверу, используя метод [`LoadObjects` сервиса данных](fo_data-service.html) - -``` csharp -var credits = DataServiceProvider.DataService.LoadObjects(lcs).Cast<Кредит>(); -``` - -## Пример - -Пример использования `LoadingCustomizationStruct` доступен по адресу: [https://github.com/Flexberry/FlexberryORM-DemoApp/blob/master/FlexberryORM/CDLIB/CDADMTEST/Form1.cs](https://github.com/Flexberry/FlexberryORM-DemoApp/blob/master/FlexberryORM/CDLIB/CDADMTEST/Form1.cs). - +--- +title: Настройка параметров чтения (LCS) +sidebar: flexberry-orm_sidebar +keywords: Flexberry ORM, сервис данных, lcs, ограничение, вычитка, фильтрация, loading +summary: Настройка параметров выборки данных LoadingCustomizationStruct, типы данных, представление, ограничение, постраничная загрузка +toc: true +permalink: ru/fo_loading-customization-struct.html +lang: ru +--- + +`LoadingCustomizationStruct` - это класс Flexberry ORM для задания параметров выборки данных (в т.ч. ограничение), реализующий собственное API, в отличие от альтернативного варианта на основе LINQ. `LoadingCustomizationStruct` позволяет полностью настроить параметры [сервиса данных](fo_construction-ds.html) для операций чтения объектов данных. + +Удобно создавать структуру `LoadingCustomizationStruct` с помощью статического метода `GetSimpleStruct`. + +``` csharp +LoadingCustomizationStruct lcs = LoadingCustomizationStruct.GetSimpleStruct(typeof(Шапка), "ШапкаE"); +``` + +## Параметры `LoadingCustomizationStruct` + +`LoadingCustomizationStruct` позволяет настраивать следующие параметры чтения: + +* `View` — указывает [представление](fd_view-definition.html), в соответствии с которым будет выполнено чтение; +* `ReturnTop` — указание количества возвращаемых записей; +* `LoadingTypes` — указывает классы данных, чьи экземпляры требуется читать ([пример](fo_reading-several-types-objects.html)); +* `ColumnsSort` — параметры сортировки возвращаемых результатов; +* `ColumnsOrder` — порядок следования свойств объекта данных в результирующей строке с разделителями, актуально, если для чтения используется метод [сервиса данных](fo_construction-ds.html) `LoadStringedObjectView`. +* `InitDataCopy` — включение или отключение инициализации [копии данных](fo_data-object-copy.html) при вычитке данных. +* `LimitFunction` — [ограничение на зачитываемые объекты данных](fo_limit-function.html), с сервера будут возвращены только те объекты, что удовлетворяют данному ограничению; +* `Distinct` — получение различных данных (используется, например, с методом [LoadRawValues SQLDataService](fo_standard-data-services.html)). +* `LoadingBufferSize` — размер порции при [порционном чтении](fo_reading-portion.html); +* `RowNumber` — указание диапазона индексов загружаемых объектов, `lcs.RowNumber = new RowNumberDef(2, 5);` (удобно, например, для постраничного вывода). + +{% include note.html content="__Представление и ограничение:__ Представление `View` должно содержать в себе все свойства, которые используются в ограничении `LimitFunction`, чтобы не произошло ошибки или неверного счёта. Если есть потребность расширить [представление](fd_view-definition.html) в соответствии с функцией ограничения `LimitFunction`, можно воспользоваться специальным классом [ViewPropertyAppender](fo_view-property-appender.html)." %} + +## Применение `LoadingCustomizationStruct` + +Чтобы вычитать набор данных из базы в память, необходимо + +1.Создать объект типа ICSSoft.STORMNET.Business.LoadingCustomizationStruct + +``` csharp +LoadingCustomizationStruct lcs = LoadingCustomizationStruct.GetSimpleStruct(тип, представление); + +``` + +2.Возможно вручную установить [представление](fd_view-definition.html) + +``` csharp +lcs.View = Клиент.Views.КлиентE; +``` + +3.Установить тип вычитываемых объектов + +``` csharp +lcs.LoadingTypes=new Type[) {typeof(Кредит)}; +``` + +4.Наложить [ограничение](fo_limit-function.html) на вычитываемые объекты (если ограничение не будет наложено - вычитаются все объекты такого типа) + +``` csharp +lcs.LimitFunction = <Объект типа ICSSoft.STORMNET.FunctionalLanguage.Function> +``` + +5.Настроить другие параметры чтения (не обязательно) +6.Сделать запрос к серверу, используя метод [`LoadObjects` сервиса данных](fo_data-service.html) + +``` csharp +IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. +IDataService ds = mainUnityContainer.Resolve(); +``` + +## Пример + +Пример использования `LoadingCustomizationStruct` доступен по адресу: [https://github.com/Flexberry/FlexberryORM-DemoApp/blob/master/FlexberryORM/CDLIB/CDADMTEST/Form1.cs](https://github.com/Flexberry/FlexberryORM-DemoApp/blob/master/FlexberryORM/CDLIB/CDADMTEST/Form1.cs). diff --git a/pages/products/flexberry-orm/data-service/fo_processing-one-object.ru.md b/pages/products/flexberry-orm/data-service/fo_processing-one-object.ru.md index 18f1d32ad..17248553a 100644 --- a/pages/products/flexberry-orm/data-service/fo_processing-one-object.ru.md +++ b/pages/products/flexberry-orm/data-service/fo_processing-one-object.ru.md @@ -1,44 +1,46 @@ ---- -title: Обработка одного объекта -sidebar: flexberry-orm_sidebar -keywords: Flexberry ORM, сервис данных -summary: Особенности обновления объекта данных с использованием сервиса данных -toc: true -permalink: ru/fo_processing-one-object.html -lang: ru ---- - -Для того чтобы обновить данные в [хранилище для объекта данных](fo_storing-data-objects.html), необходимо выполнить метод [сервиса данных](fo_data-service.html) `UpdateObject`. - -Для того чтобы прочитать объект данных из хранилища по его [ключу](fo_primary-keys-objects.html) необходимо вызвать метод сервиса данных `LoadObject` (объект данных будет прочитан в [представлении](fd_view-definition.html), объявленном как «*»). - -Ниже приведён пример, когда созданный объект данных создаётся в хранилище, а затем читается по [ключу](fo_primary-keys-objects.html). - -```csharp -static void Main(string[) args) -{ - //Сохранение одного объекта - Страна странакоторуюпишем = new Страна(); - странакоторуюпишем.Наименование="Россия"; - UpdateObject(странакоторуюпишем); - Console.WriteLine("Конец сохранения"); - //чтение одного объекта - Страна странакоторуючитаем = new Страна(); - странакоторуючитаем.SetExistObjectPrimaryKey(странакоторуюпишем.__PrimaryKey); - LoadObject(странакоторуючитаем); - Console.WriteLine("Конец чтения, страна {0}", странакоторуючитаем.Наименование); - Console.Read(); -} -private static void UpdateObject(DataObject dparam) -{ - IDataService ds = DataServiceProvider.DataService; - ds.UpdateObject(ref dparam); -} -private static void LoadObject(DataObject dparam) -{ - IDataService ds = DataServiceProvider.DataService; - ds.LoadObject(dparam); -} -``` - -Важно учитывать `.Net`-атрибут [AutoAltered](fo_object-status.html)! Если прочитан некоторый объект данных, изменены его свойства и выполняется обновление в хранилище, то если объект данных не является `AutoAltered`, не следует ждать от [сервиса данных](fo_data-service.html) обновления данных в хранилище без «ручной» установки этому объекту статуса `Altered`. +--- +title: Обработка одного объекта +sidebar: flexberry-orm_sidebar +keywords: Flexberry ORM, сервис данных +summary: Особенности обновления объекта данных с использованием сервиса данных +toc: true +permalink: ru/fo_processing-one-object.html +lang: ru +--- + +Для того чтобы обновить данные в [хранилище для объекта данных](fo_storing-data-objects.html), необходимо выполнить метод [сервиса данных](fo_data-service.html) `UpdateObject`. + +Для того чтобы прочитать объект данных из хранилища по его [ключу](fo_primary-keys-objects.html) необходимо вызвать метод сервиса данных `LoadObject` (объект данных будет прочитан в [представлении](fd_view-definition.html), объявленном как «*»). + +Ниже приведён пример, когда созданный объект данных создаётся в хранилище, а затем читается по [ключу](fo_primary-keys-objects.html). + +```csharp +static void Main(string[) args) +{ + //Сохранение одного объекта + Страна странакоторуюпишем = new Страна(); + странакоторуюпишем.Наименование="Россия"; + UpdateObject(странакоторуюпишем); + Console.WriteLine("Конец сохранения"); + //чтение одного объекта + Страна странакоторуючитаем = new Страна(); + странакоторуючитаем.SetExistObjectPrimaryKey(странакоторуюпишем.__PrimaryKey); + LoadObject(странакоторуючитаем); + Console.WriteLine("Конец чтения, страна {0}", странакоторуючитаем.Наименование); + Console.Read(); +} +private static void UpdateObject(DataObject dparam) +{ + IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. + IDataService ds = mainUnityContainer.Resolve(); + ds.UpdateObject(ref dparam); +} + private static void LoadObject(DataObject dparam) +{ + IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. + IDataService ds = mainUnityContainer.Resolve(); + ds.LoadObject(dparam); +} +``` + +Важно учитывать `.Net`-атрибут [AutoAltered](fo_object-status.html)! Если прочитан некоторый объект данных, изменены его свойства и выполняется обновление в хранилище, то если объект данных не является `AutoAltered`, не следует ждать от [сервиса данных](fo_data-service.html) обновления данных в хранилище без «ручной» установки этому объекту статуса `Altered`. diff --git a/pages/products/flexberry-orm/data-service/fo_reading-portion.ru.md b/pages/products/flexberry-orm/data-service/fo_reading-portion.ru.md index d6ef52db5..ce263cfb2 100644 --- a/pages/products/flexberry-orm/data-service/fo_reading-portion.ru.md +++ b/pages/products/flexberry-orm/data-service/fo_reading-portion.ru.md @@ -1,38 +1,39 @@ ---- -title: Порционное чтение -sidebar: flexberry-orm_sidebar -keywords: Flexberry ORM, сервис данных -summary: Правила использования порционного чтения -toc: true -permalink: ru/fo_reading-portion.html -lang: ru ---- - -Весьма удобной возможностью является чтение объектов данных порциями, по частям. Существует возможность вызвать операцию чтения таким образом, чтобы кроме порции объектов данных, [сервис данных](fo_data-service.html) возвратил некоторое состояние чтения. Передавая последующим операциям чтения это состояние, можно получать очередные порции. - -Для выполнения порционного чтения необходимо: - -* Установить в [LoadingCustomizationStruct](fo_loading-customization-struct.html) дополнительно размер порции через свойство `LoadingCustomizationStruct`. -* Вызвать метод чтения объектов с параметрами `LoadingCustomizationStruct` и состояния, получить состояние. -* Выполнять последующее дочитывание по состоянию. - -``` csharp -IDataService ds = DataServiceProvider.DataService; -LoadingCustomizationStruct lcs = LoadingCustomizationStruct.GetSimpleStruct(typeof(Автор), Автор.Views.Главное); -lcs.LoadingBufferSize = 1; // Размер порции. -object state = null; // Сюда вернётся состояние сервиса данных. -DataObject[) dataobjects = ds.LoadObjects(lcs, ref state); // Вызываем сервис данных, состояние запоминается. -prvPrintPortion(dataobjects); // Печатаем первую порцию. -while (dataobjects.Length > 0) // Пока ещё что-то возвращается. -{ - Console.WriteLine("Нажмите Enter, чтобы прочитать очередную порцию авторов."); - Console.ReadLine(); - dataobjects = ds.LoadObjects(ref state); // Прочитываем очередную порцию. Lcs уже не передаём. - prvPrintPortion(dataobjects); // Печатаем очередную порцию. -} - -Console.WriteLine("Больше авторов нет. Конец."); -Console.Read(); -``` - -{% include note.html content="Сигнатуры вызова метода `LoadObjects` __разные__. Для дочитывания данных используется вызов метода с 1 параметром `ref state`." %} +--- +title: Порционное чтение +sidebar: flexberry-orm_sidebar +keywords: Flexberry ORM, сервис данных +summary: Правила использования порционного чтения +toc: true +permalink: ru/fo_reading-portion.html +lang: ru +--- + +Весьма удобной возможностью является чтение объектов данных порциями, по частям. Существует возможность вызвать операцию чтения таким образом, чтобы кроме порции объектов данных, [сервис данных](fo_data-service.html) возвратил некоторое состояние чтения. Передавая последующим операциям чтения это состояние, можно получать очередные порции. + +Для выполнения порционного чтения необходимо: + +* Установить в [LoadingCustomizationStruct](fo_loading-customization-struct.html) дополнительно размер порции через свойство `LoadingCustomizationStruct`. +* Вызвать метод чтения объектов с параметрами `LoadingCustomizationStruct` и состояния, получить состояние. +* Выполнять последующее дочитывание по состоянию. + +``` csharp +IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. +IDataService ds = mainUnityContainer.Resolve(); +LoadingCustomizationStruct lcs = LoadingCustomizationStruct.GetSimpleStruct(typeof(Автор), Автор.Views.Главное); +lcs.LoadingBufferSize = 1; // Размер порции. +object state = null; // Сюда вернётся состояние сервиса данных. +DataObject[) dataobjects = ds.LoadObjects(lcs, ref state); // Вызываем сервис данных, состояние запоминается. +prvPrintPortion(dataobjects); // Печатаем первую порцию. +while (dataobjects.Length > 0) // Пока ещё что-то возвращается. +{ + Console.WriteLine("Нажмите Enter, чтобы прочитать очередную порцию авторов."); + Console.ReadLine(); + dataobjects = ds.LoadObjects(ref state); // Прочитываем очередную порцию. Lcs уже не передаём. + prvPrintPortion(dataobjects); // Печатаем очередную порцию. +} + +Console.WriteLine("Больше авторов нет. Конец."); +Console.Read(); +``` + +> Сигнатуры вызова метода `LoadObjects` __разные__. Для дочитывания данных используется вызов метода с 1 параметром `ref state`. diff --git a/pages/products/flexberry-orm/data-service/fo_sql-data-service.ru.md b/pages/products/flexberry-orm/data-service/fo_sql-data-service.ru.md index 84f58359d..bc967832f 100644 --- a/pages/products/flexberry-orm/data-service/fo_sql-data-service.ru.md +++ b/pages/products/flexberry-orm/data-service/fo_sql-data-service.ru.md @@ -1,644 +1,650 @@ ---- -title: SQLDataService -sidebar: flexberry-orm_sidebar -keywords: Flexberry ORM, сервис данных -summary: Возможности, способы, методы работы с запросами, операциями и событиями -toc: true -permalink: ru/fo_sql-data-service.html -lang: ru ---- - -[Сервис данных](fo_data-service.html), работающий с реляционными хранилищами. - -Является абстрактным классом, от него наследуется - -* [`MSSQLDataService`](fo_mssql-data-service.html), -* [`ODBCDataService`](fo_odbc-data-service.html), -* [`OracleDataService`](fo_oracle-data-service.html), -* [`PostgresDataService`](fo_postgres-data-service.html). - -## Основные возможности SQLDataService - -Поскольку `SQLDataService` реализует интерфейс `ICSSoft.STORMNET.Business.IDataService`, то он поддерживает все [методы, определенные в данном интерфейсе](fo_data-service.html). -Следует отметить, что часть методов лишь декларируется в классе `SQLDataService`, а их реализация должна быть выполнена в классах-наследниках. - -### Дополнительные способы загрузки данных - -#### LoadRawValues - -__Назначение__: Загрузка без создания объектов при необходимости получить DISTINCT данные. - Стандартные методы зачитки получают [PrimaryKey](fo_primary-keys-objects.html) для возможности правильного создания объектов данных. Соответственно, DISTINCT с [PrimaryKey](fo_primary-keys-objects.html) в запросе не даёт эффекта (ключи уникальные, поэтому никакой группировки результатов не произойдёт - они все разные). Данный метод возвращает обычный двумерный массив (как это делает `ADO.NET`). - -__Параметры__: - -`customizationStruct` - Структура [LoadingCustomizationStruct](fo_loading-customization-struct.html), определяющая, что и как грузить. Должен быть указан параметр `Distinct`. - -__Сигнатура__: - -```csharp - virtual public object[][] LoadRawValues(LoadingCustomizationStruct customizationStruct) -``` - -__Пример__: - -```csharp -SQLDataService ds = (SQLDataService)DataServiceProvider.DataService; -View v = new View(); -v.DefineClassType = typeof (Door); -v.AddProperty("Street.Name"); -LoadingCustomizationStruct lcs = LoadingCustomizationStruct.GetSimpleStruct(typeof(Door), v); -lcs.Distinct = false; //Получим двумерный массив свойств без DISTINCT в верхнем SELECT-е -object[][] loadDistinctValues = ds.LoadRawValues(lcs); -string s = loadDistinctValues.Length.ToString(); - -lcs.Distinct = true; //Получим двумерный массив свойств с DISTINCT в верхнем SELECT-е -object[][] loadDistinctValues1 = ds.LoadRawValues(lcs); -string s1 = loadDistinctValues1.Length.ToString(); -``` - -#### SecondLoadObject - -__Назначение__: Метод для дочитки объекта данных. -Загруженные ранее свойства не затираются, изменённые свойства не затираются. Подменяются поштучно свойства копии данных. Перед использованием рекомендуется ознакомиться с описанием в статье [Дочитка объекта данных](fo_additional-loading.html). - -__Параметры__: - -* `dataObjectView` - представление -* `dataObject` - бъект данных, который требуется загрузить -* `checkExistingObject` - проверять ли существование объекта в хранилище -* `dataObjectCache` - кэш - -__Сигнатура__: - -```csharp -protected virtual void SecondLoadObject(View dataObjectView, DataObject dataObject, bool checkExistingObject, DataObjectCache dataObjectCache) -``` - -## Дополнительные способы обновления данных - -### UpdateObjectsOrdered - -__Назначение__: Обновить объекты данных в указанном порядке. - -`SQLDataService` умеет сам выстраивать порядок запросов на обновление объектов данных. Особенно это актуально, когда есть большое количество разнотипных объектов в одной транзакции. К сожалению, не всегда есть возможность автоматизированно вычислить правильный порядок запросов. В первую очередь, это относится к ситуациям, когда в графе типов есть циклы. Для решения этой проблемы предлагается использовать данный метод, который выполняет обновление объектов последовательно в том порядке, в котором они приходят в этот метод. - -__Параметры__: - -* `objects` - обновляемые объекты -* `alwaysThrowException` - Если произошла ошибка в базе данных, не пытаться выполнять других запросов, сразу взводить ошибку и откатывать транзакцию. - -__Сигнатура__: - - ```csharp -virtual public void UpdateObjectsOrdered(ref DataObject[] objects, bool alwaysThrowException = true) -``` - -__Пример__: - - ```csharp -protected void UpdateButtonClick(object sender, EventArgs e) -{ - SQLDataService ds = (SQLDataService)DataServiceProvider.DataService; - var ko = ds.Query<КритерийОценки>(КритерийОценки.Views.КритерийОценкиE).First(o => o.Описание.StartsWith("kirlim")); - ko.Описание = "kirlim-birlim"; -DataObject[] dObjs = new DataObject[] { ko }; - ds.UpdateObjectsOrdered(ref dObjs); -} -``` - -### Выполнение операций в рамках указанных коннекции и транзакции - -#### LoadObjectByExtConn - -__Назначение__: Загрузка объекта с указанной коннекцией в рамках указанной транзакции - -__Параметры__: - -* `dataObjectView` - Представление, по которому будет зачитываться объект. -* `dobject` - Объект, который будет дочитываться/зачитываться. -* `сlearDataObject` - Следует ли при зачитке очистить поля существующего объекта данных. -* `сheckExistingObject` - Проверить существование встречающихся при зачитке объектов. -* `dataObjectCache` - Кэш объектов. -* `connection` - Коннекция, через которую будет происходить зачитка. -* `transaction` - Транзакция, в рамках которой будет проходить зачитка. - -__Сигнатура__: - - ```csharp -public virtual void LoadObjectByExtConn( - View dataObjectView, - DataObject dobject, - bool сlearDataObject, - bool сheckExistingObject, - DataObjectCache dataObjectCache, - IDbConnection connection, - IDbTransaction transaction) -``` - -#### LoadObjectsByExtConn - -__Назначение__: Загрузка объектов с использованием указанной коннекции и транзакции - -__Параметры__: - -* `customizationStruct` - Структура, определяющая, что и как грузить. -* `state` - Состояние вычитки(для последующей дочитки, если используется [порционное чтение](fo_reading-portion.html), размер порции задаётся в `customizationStruct.LoadingBufferSize`) -* `dataObjectCache` - Кэш объектов для зачитки. -* `connection` - Коннекция, через которую будут выполнена зачитка. -* `transaction` - Транзакция, в рамках которой будет выполнена зачитка. - -__Сигнатура__: - -```csharp -public virtual DataObject[] LoadObjectsByExtConn( - LoadingCustomizationStruct customizationStruct, - ref object state, - DataObjectCache dataObjectCache, - IDbConnection connection, - IDbTransaction transaction) -``` - -#### ReadFirstByExtConn - -__Назначение__: Получение первой порции при [порционном чтении](fo_reading-portion.html) с использованием указанной коннекции и транзакции. Кроме порции объектов данных, сервис данных возвращает состояние чтения `state`. Это состояние передается сервису данных для получения очередных порций (см. следующий метод). -Аналог предыдущего метода, но вместо настроечной структуры выборка определяется текстом запроса. - -__Параметры__: - -* `Query` - Текст запроса для выборки данных -* `state` - Состояние вычитки(для последующей дочитки) -* `LoadingBufferSize` - размер порции -* `Connection` - Коннекция, через которую будут выполнена зачитка -* `Transaction` - Транзакция, в рамках которой будет выполнена зачитка - -__Сигнатура__: - -```csharp -public virtual object[][] ReadFirstByExtConn(string Query, ref object State, int LoadingBufferSize, System.Data.IDbConnection Connection, System.Data.IDbTransaction Transaction) -``` - -#### ReadNextByExtConn - -__Назначение__: Получение очередных порций при [порционном чтении](fo_reading-portion.html). Должен предшествовать вызов одного из двух вышеуказанных методов с получением состояния `state`. - -__Параметры__: - -* `state` - Состояние вычитки(для последующей дочитки) -* `LoadingBufferSize` - размер порции - -__Сигнатура__: - -```csharp -public virtual object[][] ReadNextByExtConn(ref object State, int LoadingBufferSize) -``` - -#### UpdateObjectsByExtConn - -__Назначение__: Обновить хранилище по объектам с использованием указанной коннекции и транзакции. - -{% include note.html content="Если параметр `alwaysThrowException`=`true`, всегда взводится ошибка. Иначе, выполнение продолжается. Однако, при этом есть опасность преждевременного окончания транзакции, с переходом для остальных запросов режима транзакционности в autocommit. Проявлением проблемы являются ошибки вроде: The COMMIT TRANSACTION request has no corresponding BEGIN TRANSACTION." %} - -__Параметры__: - -* `objects` - Объекты для обновления. -* `dataObjectCache` - Кеш объектов. -* `alwaysThrowException` - Если произошла ошибка в базе данных, не пытаться выполнять других запросов, сразу взводить ошибку и откатывать транзакцию. -* `connection` - Коннекция (не забудьте закрыть). -* `transaction` - Транзакция (не забудьте завершить). - -__Сигнатура__: - -```csharp -public virtual void UpdateObjectsByExtConn(ref DataObject[] objects, DataObjectCache dataObjectCache, bool alwaysThrowException, IDbConnection connection, IDbTransaction transaction) -``` - -## Генерация текстов SQL-запросов - -### GenerateQueriesForUpdateObjects - -__Назначение__: Генерация запросов для изменения объектов - -__Параметры__: - -* `deleteQueries` - Запросы для удаление (выходной параметр) -* `deleteTables` - Таблицы, из которых будет проведено удаление данных (выходной параметр) -* `updateQueries` - Сгенерированные запросы для изменения (выходной параметр). -* `updateTables` - Таблицы, в которых будет проведено изменение данных (выходной параметр). -* `insertQueries` - Сгенерированные запросы для добавления (выходной параметр). -* `insertTables` - Таблицы, в которые будет проведена вставка данных (выходной параметр). -* `tableOperations` - Операции, которые будут произведены над таблицами (выходной параметр). -* `queryOrder` - Порядок исполнения генерируемых запросов, задаваемый именами таблиц (выходной параметр). -* `checkLoadedProps` - Проверять ли загруженность свойств. -* `processingObjects` - Текущие обрабатываемые объекты (то есть объекты, которые данный сервис данных планирует подтвердить в БД в текущей транзакции). Выходной параметр. -* `dataObjectCache` - Кэш объектов данных. -* `auditObjects` - Список объектов, которые необходимо записать в аудит (выходной параметр). Заполняется в том случае, когда передан не null и текущий сервис аудита включен. -* `dobjects` - Объекты, для которых генерируются запросы. - -__Сигнатура__: - -```csharp -public virtual void GenerateQueriesForUpdateObjects( - StringCollection deleteQueries, - StringCollection deleteTables, - StringCollection updateQueries, - StringCollection updateTables, - StringCollection insertQueries, - StringCollection insertTables, - SortedList tableOperations, - StringCollection queryOrder, - bool checkLoadedProps, - System.Collections.ArrayList processingObjects, - DataObjectCache dataObjectCache, - params ICSSoft.STORMNET.DataObject[] dobjects) -``` - -В данной перегрузке дополнительно возвращается список объектов, для которых необходимо создание записей аудита: - -```csharp -public virtual void GenerateQueriesForUpdateObjects( - StringCollection deleteQueries, - StringCollection deleteTables, - StringCollection updateQueries, - StringCollection updateTables, - StringCollection insertQueries, - StringCollection insertTables, - SortedList tableOperations, - StringCollection queryOrder, - bool checkLoadedProps, - ArrayList processingObjects, - DataObjectCache dataObjectCache, - List auditObjects, - params ICSSoft.STORMNET.DataObject[] dobjects) -``` - -### GenerateSQLSelect - -__Назначение__: Получить запрос на вычитку данных - -__Параметры__: - -* `customizationStruct` - настройка выборки -* `StorageStruct` - возвращается соответствующая структура выборки - -__Возвращаемый результат__: запрос - -__Сигнатура__: - -```csharp -// 1. -public virtual string GenerateSQLSelect(LoadingCustomizationStruct customizationStruct, bool ForReadValues, out STORMDO.Business.StorageStructForView[] StorageStruct, bool Optimized) - -// 2. -public virtual string GenerateSQLSelect(LoadingCustomizationStruct customizationStruct, bool Optimized) -``` - -### GetLeftJoinExpression - -__Назначение__: Получить LeftJoin выражение - -__Параметры__: - -* `subTable` - имя таблицы -* `subTableAlias` - псевдоним таблицы -* `parentAliasWithKey` -* `subTableKey` -* `subJoins` -* `baseOutline` - -__Сигнатура__: - -```csharp -public virtual void GetLeftJoinExpression(string subTable, string subTableAlias, string parentAliasWithKey, string subTableKey, string subJoins, string baseOutline, out string FromPart, out string WherePart) -``` - -### GetInnerJoinExpression - -__Назначение__: Получить InnerJoin выражение - -__Параметры__: - -* `subTable` - имя таблицы -* `subTableAlias` - псевдоним таблицы -* `parentAliasWithKey` -* `subTableKey` -* `subJoins` -* `baseOutline` -* `FromPart` -* `WherePart` - -__Сигнатура__: - -```csharp -public virtual void GetInnerJoinExpression(string subTable, string subTableAlias, string parentAliasWithKey, string subTableKey, string subJoins, string baseOutline, out string FromPart, out string WherePart) -``` - -### GetJoinTableModifierExpression - -__Назначение__: Вернуть модификатор для обращения к таблице (напр WITH (NOLOCK)) - -Можно перегрузить этот метод в сервисе данных-наследнике для возврата соответствующего своего модификатора. -Базовый `SQLDataService` возвращает пустую строку. - -__Сигнатура__: - -```csharp -public virtual string GetJoinTableModifierExpression() -``` - -### GetINExpression - -__Назначение__: Вернуть in выражение для where - -__Параметры__: - -`identifiers` - идентификаторы - -__Сигнатура__: - -```csharp -public virtual string GetINExpression(params string[] identifiers) -``` - -### GetIfNullExpression - -__Назначение__: Вернуть ifnull выражение - -__Параметры__: - -`identifiers` - идентификаторы - -__Сигнатура__: - -```csharp -public virtual string GetIfNullExpression(params string[] identifiers) -``` - -### PutIdentifierIntoBrackets - -__Назначение__: Оформить идентификатор - -__Параметры__: - -`identifier` - идентификатор - -__Возвращаемый результат__: оформленный идентификатор(например в кавычках) - -__Сигнатура__: - -```csharp -public virtual string PutIdentifierIntoBrackets(string identifier) -``` - -### CreateJoins - -__Назначение__: Создать join соединения - -__Параметры__: - -* `source` - источник с которого формируется соединение -* `parentAlias` - вышестоящий алиас -* `index` - индекс источника -* `keysandtypes` - ключи и типы -* `baseOutline` - смещение в запросе -* `joinscount` - количество соединений - -__Сигнатура__: - -```csharp -public virtual void CreateJoins(STORMDO.Business.StorageStructForView.PropSource source, - string parentAlias, int index, - System.Collections.ArrayList keysandtypes, - string baseOutline, out int joinscount, - out string FromPart, out string WherePart) -``` - -### `CreateJoins` - -__Назначение__: Создать join соединения - -__Параметры__: - -* `source` - источник с которого формируется соединение -* `parentAlias` - вышестоящий алиас -* `index` - индекс источника -* `keysandtypes` - ключи и типы -* `baseOutline` - смещение в запросе -* `joinscount` - количество соединений - -__Сигнатура__: - -```csharp -public virtual void CreateJoins(STORMDO.Business.StorageStructForView.PropSource source, - string parentAlias, int index, - System.Collections.ArrayList keysandtypes, - string baseOutline, out int joinscount, - out string FromPart, out string WherePart, bool MustNewGenerate) -``` - -### GenerateSQLSelectByStorageStruct - -__Назначение__: Получение SQL запроса в следующем формате - -```sql -SELECT - atr1,atr2,... atr3, - Key1,Key2,... key3 -FROM - fromjoins -``` - -__Параметры__: - -* `storageStruct` - структура хранилища -* `AddingAdvansedField` - довленные дополнительные свойства -* `AddingKeysCount` - добавленниые ключи -* `addMasterFieldsCustomizer` -* `addNotMainKeys` -* `SelectTypesIds` - -__Сигнатура__: - -```csharp -// 1. -virtual public string GenerateSQLSelectByStorageStruct(STORMDO.Business.StorageStructForView storageStruct, bool addNotMainKeys, bool addMasterFieldsCustomizer, string AddingAdvansedField, int AddingKeysCount, bool SelectTypesIds) - -// 2. -virtual public string GenerateSQLSelectByStorageStruct(STORMDO.Business.StorageStructForView storageStruct, bool addNotMainKeys, bool addMasterFieldsCustomizer, string AddingAdvansedField, int AddingKeysCount, bool SelectTypesIds, bool MustNewGenerate, bool MustDopSelect) -``` - -### ConvertSimpleValueToQueryValueString - -__Назначение__: Конвертация константных значений в строки запроса - -__Параметры__: - -`value` - значение - -__Сигнатура__: - -```csharp -public virtual string ConvertSimpleValueToQueryValueString(object value) -``` - -### ConvertValueToQueryValueString - -__Назначение__: Конвертация значений в строки запроса - -__Параметры__: - -`value` - значение - -__Сигнатура__: - -```csharp -public virtual string ConvertValueToQueryValueString(object value) -``` - -### ConvertValueToQueryValueString - -__Назначение__: Преобразование значение свойства в строку для запроса - -__Параметры__: - -* `dataobject` - объект данных -* `propname` - имя свойства - -__Сигнатура__: - -```csharp -public virtual string ConvertValueToQueryValueString(DataObject dataobject, string propname) -``` - -### LimitFunction2SQLWhere - -__Назначение__: Преобразование функции - -__Параметры__:`LimitFunction` - настроечная структура выборки - -__Сигнатура__: - -```csharp -public virtual string LimitFunction2SQLWhere(STORMFunction LimitFunction, STORMDO.Business.StorageStructForView[] StorageStruct, string[] asnameprop, bool MustNewGenerate) -``` - -### LimitFunction2SQLWhere - -__Назначение__: Преобразование функции - -__Параметры__: - -`LimitFunction` - настроечная структура выборки - -__Сигнатура__: - -```csharp -public virtual string LimitFunction2SQLWhere(STORMFunction LimitFunction) -``` - -## Выполнение операций с указанием текста запроса - -### ReadFirst - -__Назначение__: Вычитка первой партии данных при [порционном чтении](fo_reading-portion.html). Кроме порции объектов данных, сервис данных возвращает состояние чтения `state`. Это состояние передается сервису данных для получения очередных порций (см. следующий метод).Выборка определяется текстом запроса. - -__Параметры__: - -* `Query` - Текст запроса для выборки данных -* `state` - Состояние вычитки(для последующей дочитки) -* `LoadingBufferSize` - размер порции - -__Сигнатура__: - -```csharp -public virtual object[][] ReadFirst(string Query, ref object State, int LoadingBufferSize) -``` - -### ReadNext - -__Назначение__: Получение очередной порции при [порционном чтении](fo_reading-portion.html). Должен предшествовать вызов предыдущего метода с получением состояния `state`. - -__Параметры__: - -* `state` - Состояние вычитки(для последующей дочитки) -* `LoadingBufferSize` - размер порции - -__Сигнатура__: - -```csharp -public virtual object[][] ReadNext(ref object State, int LoadingBufferSize) -``` - -### ExecuteNonQuery - -__Назначение__: Выполнить запрос - -__Параметры__: - -`Query` - текст SQL-запроса - -__Возвращаемый результат__: количество задетых строк - -__Сигнатура__: - -```csharp -public virtual int ExecuteNonQuery(string Query) -``` - -## Список событий для SQLDataService - -Кроме обработки указанных событий `SQLDataService` предоставляет возможность полного переопределения логики, т.к. содержит следующие делегаты: - -```csharp -// Делегат для события создания команды. -public delegate void OnCreateCommandEventHandler(object sender, CreateCommandEventArgs e); - -// Делегат для события при генерации SQL Select запроса (перед). -public delegate void OnGenerateSQLSelectEventHandler(object sender, GenerateSQLSelectQueryEventArgs e); - -// Делегат для события при генерации SQL Select запроса (после). -public delegate void AfterGenerateSQLSelectQueryEventHandler(object sender, GenerateSQLSelectQueryEventArgs e); - -// The before update objects event handler. -public delegate void BeforeUpdateObjectsEventHandler(object sender, DataObjectsEventArgs e); - -// The after update objects event handler. -public delegate void AfterUpdateObjectsEventHandler(object sender, DataObjectsEventArgs e); -``` - -|Событие|Описание| -|:------|:------ -| OnGenerateSQLSelect | Срабатывает перед генерацией SQL SELECT'а ([пример](fo_intercept-formation-sql-query.html)). Обрабатывая это событие можно, например, добавить дополнительные условия, которые должны попасть в формируемый запрос.| -| AfterGenerateSQLSelectQuery | Срабатывает после генерации SQL SELECT'а, но до вычитки данных ([пример](fo_intercept-formation-sql-query.html)). Можно использовать для внесения изменений в сгенерированный текст запроса.| -| BeforeUpdateObjects | Срабатывает перед обновлением объектов в базе, после отработки бизнес-серверов.| -| AfterUpdateObjects | Срабатывает после обновления объектов в базе.| -| OnCreateCommand | Срабатывает при создании SQL-команды ([пример](fo_intercept-formation-sql-query.html)).| - -### Задание CommandTimeout - -Есть возможность указывать [IDbCommand.CommandTimeout](http://msdn.microsoft.com/ru-ru/library/system.data.idbcommand.commandtimeout.aspx). Для этого можно в конфигурационном файле задать параметр: - -```xml - -``` - -либо присвоить значение явно: - -```csharp -SQLDataService ds = (SQLDataService)DataServiceProvider.DataService; -ds.UseCommandTimeout = true; -ds.CommandTimeout = 60; -``` - -`UseCommandTimeout` нужно указывать обязательно. По-умолчанию этот флаг имеет значение `false`. - -Такая сложная реализация нужна для возможности включения-отключения использования уникальных значений без потери предыдущего значения таймаута. - -Также важно понимать, что при выполнении любой операции (чтение/обновление и т.д.) коннекция создаётся, а в конце закрывается. Т.е. последовательные LoadObjects будут выполнены в на разных `System.Data.IDbConnection`. - -Соответственно применяться настройка времени ожидания выполнения команды будет каждый раз заново. - -{% include note.html content="Время ожидания выполнения команды **в секундах**. Значение по умолчанию — 30 секунд." %} - -### Смена строки соединения - -`SQLDataService` поддерживает возможность смены строки соединения. Такая возможность, в частности, используется для работы с несколькими БД в одном приложении, описание доступно в [статье](fo_multibase.html). +--- +title: SQLDataService +sidebar: flexberry-orm_sidebar +keywords: Flexberry ORM, сервис данных +summary: Возможности, способы, методы работы с запросами, операциями и событиями +toc: true +permalink: ru/fo_sql-data-service.html +lang: ru +--- + +[Сервис данных](fo_data-service.html), работающий с реляционными хранилищами. + +Является абстрактным классом, от него наследуется + +* [`MSSQLDataService`](fo_mssql-data-service.html), +* [`ODBCDataService`](fo_odbc-data-service.html), +* [`OracleDataService`](fo_oracle-data-service.html), +* [`PostgresDataService`](fo_postgres-data-service.html). + +## Основные возможности SQLDataService + +Поскольку `SQLDataService` реализует интерфейс `ICSSoft.STORMNET.Business.IDataService`, то он поддерживает все [методы, определенные в данном интерфейсе](fo_data-service.html). +Следует отметить, что часть методов лишь декларируется в классе `SQLDataService`, а их реализация должна быть выполнена в классах-наследниках. + +### Дополнительные способы загрузки данных + +#### LoadRawValues + +__Назначение__: Загрузка без создания объектов при необходимости получить DISTINCT данные. + Стандартные методы зачитки получают [PrimaryKey](fo_primary-keys-objects.html) для возможности правильного создания объектов данных. Соответственно, DISTINCT с [PrimaryKey](fo_primary-keys-objects.html) в запросе не даёт эффекта (ключи уникальные, поэтому никакой группировки результатов не произойдёт - они все разные). Данный метод возвращает обычный двумерный массив (как это делает `ADO.NET`). + +__Параметры__: + +`customizationStruct` - Структура [LoadingCustomizationStruct](fo_loading-customization-struct.html), определяющая, что и как грузить. Должен быть указан параметр `Distinct`. + +__Сигнатура__: + +```csharp + virtual public object[][] LoadRawValues(LoadingCustomizationStruct customizationStruct) +``` + +__Пример__: + +```csharp +IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. +IDataService ds = mainUnityContainer.Resolve(); +SQLDataService sqldataservice = (SQLDataService)ds; +View v = new View(); +v.DefineClassType = typeof (Door); +v.AddProperty("Street.Name"); +LoadingCustomizationStruct lcs = LoadingCustomizationStruct.GetSimpleStruct(typeof(Door), v); +lcs.Distinct = false; //Получим двумерный массив свойств без DISTINCT в верхнем SELECT-е +object[][] loadDistinctValues = sqldataservice.LoadRawValues(lcs); +string s = loadDistinctValues.Length.ToString(); + +lcs.Distinct = true; //Получим двумерный массив свойств с DISTINCT в верхнем SELECT-е +object[][] loadDistinctValues1 = sqldataservice.LoadRawValues(lcs); +string s1 = loadDistinctValues1.Length.ToString(); +``` + +#### SecondLoadObject + +__Назначение__: Метод для дочитки объекта данных. +Загруженные ранее свойства не затираются, изменённые свойства не затираются. Подменяются поштучно свойства копии данных. Перед использованием рекомендуется ознакомиться с описанием в статье [Дочитка объекта данных](fo_additional-loading.html). + +__Параметры__: + +* `dataObjectView` - представление +* `dataObject` - бъект данных, который требуется загрузить +* `checkExistingObject` - проверять ли существование объекта в хранилище +* `dataObjectCache` - кэш + +__Сигнатура__: + +```csharp +protected virtual void SecondLoadObject(View dataObjectView, DataObject dataObject, bool checkExistingObject, DataObjectCache dataObjectCache) +``` + +## Дополнительные способы обновления данных + +### UpdateObjectsOrdered + +__Назначение__: Обновить объекты данных в указанном порядке. + +`SQLDataService` умеет сам выстраивать порядок запросов на обновление объектов данных. Особенно это актуально, когда есть большое количество разнотипных объектов в одной транзакции. К сожалению, не всегда есть возможность автоматизированно вычислить правильный порядок запросов. В первую очередь, это относится к ситуациям, когда в графе типов есть циклы. Для решения этой проблемы предлагается использовать данный метод, который выполняет обновление объектов последовательно в том порядке, в котором они приходят в этот метод. + +__Параметры__: + +* `objects` - обновляемые объекты +* `alwaysThrowException` - Если произошла ошибка в базе данных, не пытаться выполнять других запросов, сразу взводить ошибку и откатывать транзакцию. + +__Сигнатура__: + + ```csharp +virtual public void UpdateObjectsOrdered(ref DataObject[] objects, bool alwaysThrowException = true) +``` + +__Пример__: + + ```csharp +protected void UpdateButtonClick(object sender, EventArgs e) +{ + IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. + IDataService ds = mainUnityContainer.Resolve(); + SQLDataService sqldataservice = (SQLDataService)ds; + var ko = sqldataservice.Query<КритерийОценки>(КритерийОценки.Views.КритерийОценкиE).First(o => o.Описание.StartsWith("kirlim")); + ko.Описание = "kirlim-birlim"; +DataObject[] dObjs = new DataObject[] { ko }; + ds.UpdateObjectsOrdered(ref dObjs); +} +``` + +### Выполнение операций в рамках указанных коннекции и транзакции + +#### LoadObjectByExtConn + +__Назначение__: Загрузка объекта с указанной коннекцией в рамках указанной транзакции + +__Параметры__: + +* `dataObjectView` - Представление, по которому будет зачитываться объект. +* `dobject` - Объект, который будет дочитываться/зачитываться. +* `сlearDataObject` - Следует ли при зачитке очистить поля существующего объекта данных. +* `сheckExistingObject` - Проверить существование встречающихся при зачитке объектов. +* `dataObjectCache` - Кэш объектов. +* `connection` - Коннекция, через которую будет происходить зачитка. +* `transaction` - Транзакция, в рамках которой будет проходить зачитка. + +__Сигнатура__: + + ```csharp +public virtual void LoadObjectByExtConn( + View dataObjectView, + DataObject dobject, + bool сlearDataObject, + bool сheckExistingObject, + DataObjectCache dataObjectCache, + IDbConnection connection, + IDbTransaction transaction) +``` + +#### LoadObjectsByExtConn + +__Назначение__: Загрузка объектов с использованием указанной коннекции и транзакции + +__Параметры__: + +* `customizationStruct` - Структура, определяющая, что и как грузить. +* `state` - Состояние вычитки(для последующей дочитки, если используется [порционное чтение](fo_reading-portion.html), размер порции задаётся в `customizationStruct.LoadingBufferSize`) +* `dataObjectCache` - Кэш объектов для зачитки. +* `connection` - Коннекция, через которую будут выполнена зачитка. +* `transaction` - Транзакция, в рамках которой будет выполнена зачитка. + +__Сигнатура__: + +```csharp +public virtual DataObject[] LoadObjectsByExtConn( + LoadingCustomizationStruct customizationStruct, + ref object state, + DataObjectCache dataObjectCache, + IDbConnection connection, + IDbTransaction transaction) +``` + +#### ReadFirstByExtConn + +__Назначение__: Получение первой порции при [порционном чтении](fo_reading-portion.html) с использованием указанной коннекции и транзакции. Кроме порции объектов данных, сервис данных возвращает состояние чтения `state`. Это состояние передается сервису данных для получения очередных порций (см. следующий метод). +Аналог предыдущего метода, но вместо настроечной структуры выборка определяется текстом запроса. + +__Параметры__: + +* `Query` - Текст запроса для выборки данных +* `state` - Состояние вычитки(для последующей дочитки) +* `LoadingBufferSize` - размер порции +* `Connection` - Коннекция, через которую будут выполнена зачитка +* `Transaction` - Транзакция, в рамках которой будет выполнена зачитка + +__Сигнатура__: + +```csharp +public virtual object[][] ReadFirstByExtConn(string Query, ref object State, int LoadingBufferSize, System.Data.IDbConnection Connection, System.Data.IDbTransaction Transaction) +``` + +#### ReadNextByExtConn + +__Назначение__: Получение очередных порций при [порционном чтении](fo_reading-portion.html). Должен предшествовать вызов одного из двух вышеуказанных методов с получением состояния `state`. + +__Параметры__: + +* `state` - Состояние вычитки(для последующей дочитки) +* `LoadingBufferSize` - размер порции + +__Сигнатура__: + +```csharp +public virtual object[][] ReadNextByExtConn(ref object State, int LoadingBufferSize) +``` + +#### UpdateObjectsByExtConn + +__Назначение__: Обновить хранилище по объектам с использованием указанной коннекции и транзакции. + +{% include note.html content="Если параметр `alwaysThrowException`=`true`, всегда взводится ошибка. Иначе, выполнение продолжается. Однако, при этом есть опасность преждевременного окончания транзакции, с переходом для остальных запросов режима транзакционности в autocommit. Проявлением проблемы являются ошибки вроде: The COMMIT TRANSACTION request has no corresponding BEGIN TRANSACTION." %} + +__Параметры__: + +* `objects` - Объекты для обновления. +* `dataObjectCache` - Кеш объектов. +* `alwaysThrowException` - Если произошла ошибка в базе данных, не пытаться выполнять других запросов, сразу взводить ошибку и откатывать транзакцию. +* `connection` - Коннекция (не забудьте закрыть). +* `transaction` - Транзакция (не забудьте завершить). + +__Сигнатура__: + +```csharp +public virtual void UpdateObjectsByExtConn(ref DataObject[] objects, DataObjectCache dataObjectCache, bool alwaysThrowException, IDbConnection connection, IDbTransaction transaction) +``` + +## Генерация текстов SQL-запросов + +### GenerateQueriesForUpdateObjects + +__Назначение__: Генерация запросов для изменения объектов + +__Параметры__: + +* `deleteQueries` - Запросы для удаление (выходной параметр) +* `deleteTables` - Таблицы, из которых будет проведено удаление данных (выходной параметр) +* `updateQueries` - Сгенерированные запросы для изменения (выходной параметр). +* `updateTables` - Таблицы, в которых будет проведено изменение данных (выходной параметр). +* `insertQueries` - Сгенерированные запросы для добавления (выходной параметр). +* `insertTables` - Таблицы, в которые будет проведена вставка данных (выходной параметр). +* `tableOperations` - Операции, которые будут произведены над таблицами (выходной параметр). +* `queryOrder` - Порядок исполнения генерируемых запросов, задаваемый именами таблиц (выходной параметр). +* `checkLoadedProps` - Проверять ли загруженность свойств. +* `processingObjects` - Текущие обрабатываемые объекты (то есть объекты, которые данный сервис данных планирует подтвердить в БД в текущей транзакции). Выходной параметр. +* `dataObjectCache` - Кэш объектов данных. +* `auditObjects` - Список объектов, которые необходимо записать в аудит (выходной параметр). Заполняется в том случае, когда передан не null и текущий сервис аудита включен. +* `dobjects` - Объекты, для которых генерируются запросы. + +__Сигнатура__: + +```csharp +public virtual void GenerateQueriesForUpdateObjects( + StringCollection deleteQueries, + StringCollection deleteTables, + StringCollection updateQueries, + StringCollection updateTables, + StringCollection insertQueries, + StringCollection insertTables, + SortedList tableOperations, + StringCollection queryOrder, + bool checkLoadedProps, + System.Collections.ArrayList processingObjects, + DataObjectCache dataObjectCache, + params ICSSoft.STORMNET.DataObject[] dobjects) +``` + +В данной перегрузке дополнительно возвращается список объектов, для которых необходимо создание записей аудита: + +```csharp +public virtual void GenerateQueriesForUpdateObjects( + StringCollection deleteQueries, + StringCollection deleteTables, + StringCollection updateQueries, + StringCollection updateTables, + StringCollection insertQueries, + StringCollection insertTables, + SortedList tableOperations, + StringCollection queryOrder, + bool checkLoadedProps, + ArrayList processingObjects, + DataObjectCache dataObjectCache, + List auditObjects, + params ICSSoft.STORMNET.DataObject[] dobjects) +``` + +### GenerateSQLSelect + +__Назначение__: Получить запрос на вычитку данных + +__Параметры__: + +* `customizationStruct` - настройка выборки +* `StorageStruct` - возвращается соответствующая структура выборки + +__Возвращаемый результат__: запрос + +__Сигнатура__: + +```csharp +// 1. +public virtual string GenerateSQLSelect(LoadingCustomizationStruct customizationStruct, bool ForReadValues, out STORMDO.Business.StorageStructForView[] StorageStruct, bool Optimized) + +// 2. +public virtual string GenerateSQLSelect(LoadingCustomizationStruct customizationStruct, bool Optimized) +``` + +### GetLeftJoinExpression + +__Назначение__: Получить LeftJoin выражение + +__Параметры__: + +* `subTable` - имя таблицы +* `subTableAlias` - псевдоним таблицы +* `parentAliasWithKey` +* `subTableKey` +* `subJoins` +* `baseOutline` + +__Сигнатура__: + +```csharp +public virtual void GetLeftJoinExpression(string subTable, string subTableAlias, string parentAliasWithKey, string subTableKey, string subJoins, string baseOutline, out string FromPart, out string WherePart) +``` + +### GetInnerJoinExpression + +__Назначение__: Получить InnerJoin выражение + +__Параметры__: + +* `subTable` - имя таблицы +* `subTableAlias` - псевдоним таблицы +* `parentAliasWithKey` +* `subTableKey` +* `subJoins` +* `baseOutline` +* `FromPart` +* `WherePart` + +__Сигнатура__: + +```csharp +public virtual void GetInnerJoinExpression(string subTable, string subTableAlias, string parentAliasWithKey, string subTableKey, string subJoins, string baseOutline, out string FromPart, out string WherePart) +``` + +### GetJoinTableModifierExpression + +__Назначение__: Вернуть модификатор для обращения к таблице (напр WITH (NOLOCK)) + +Можно перегрузить этот метод в сервисе данных-наследнике для возврата соответствующего своего модификатора. +Базовый `SQLDataService` возвращает пустую строку. + +__Сигнатура__: + +```csharp +public virtual string GetJoinTableModifierExpression() +``` + +### GetINExpression + +__Назначение__: Вернуть in выражение для where + +__Параметры__: + +`identifiers` - идентификаторы + +__Сигнатура__: + +```csharp +public virtual string GetINExpression(params string[] identifiers) +``` + +### GetIfNullExpression + +__Назначение__: Вернуть ifnull выражение + +__Параметры__: + +`identifiers` - идентификаторы + +__Сигнатура__: + +```csharp +public virtual string GetIfNullExpression(params string[] identifiers) +``` + +### PutIdentifierIntoBrackets + +__Назначение__: Оформить идентификатор + +__Параметры__: + +`identifier` - идентификатор + +__Возвращаемый результат__: оформленный идентификатор(например в кавычках) + +__Сигнатура__: + +```csharp +public virtual string PutIdentifierIntoBrackets(string identifier) +``` + +### CreateJoins + +__Назначение__: Создать join соединения + +__Параметры__: + +* `source` - источник с которого формируется соединение +* `parentAlias` - вышестоящий алиас +* `index` - индекс источника +* `keysandtypes` - ключи и типы +* `baseOutline` - смещение в запросе +* `joinscount` - количество соединений + +__Сигнатура__: + +```csharp +public virtual void CreateJoins(STORMDO.Business.StorageStructForView.PropSource source, + string parentAlias, int index, + System.Collections.ArrayList keysandtypes, + string baseOutline, out int joinscount, + out string FromPart, out string WherePart) +``` + +### `CreateJoins` + +__Назначение__: Создать join соединения + +__Параметры__: + +* `source` - источник с которого формируется соединение +* `parentAlias` - вышестоящий алиас +* `index` - индекс источника +* `keysandtypes` - ключи и типы +* `baseOutline` - смещение в запросе +* `joinscount` - количество соединений + +__Сигнатура__: + +```csharp +public virtual void CreateJoins(STORMDO.Business.StorageStructForView.PropSource source, + string parentAlias, int index, + System.Collections.ArrayList keysandtypes, + string baseOutline, out int joinscount, + out string FromPart, out string WherePart, bool MustNewGenerate) +``` + +### GenerateSQLSelectByStorageStruct + +__Назначение__: Получение SQL запроса в следующем формате + +```sql +SELECT + atr1,atr2,... atr3, + Key1,Key2,... key3 +FROM + fromjoins +``` + +__Параметры__: + +* `storageStruct` - структура хранилища +* `AddingAdvansedField` - довленные дополнительные свойства +* `AddingKeysCount` - добавленниые ключи +* `addMasterFieldsCustomizer` +* `addNotMainKeys` +* `SelectTypesIds` + +__Сигнатура__: + +```csharp +// 1. +virtual public string GenerateSQLSelectByStorageStruct(STORMDO.Business.StorageStructForView storageStruct, bool addNotMainKeys, bool addMasterFieldsCustomizer, string AddingAdvansedField, int AddingKeysCount, bool SelectTypesIds) + +// 2. +virtual public string GenerateSQLSelectByStorageStruct(STORMDO.Business.StorageStructForView storageStruct, bool addNotMainKeys, bool addMasterFieldsCustomizer, string AddingAdvansedField, int AddingKeysCount, bool SelectTypesIds, bool MustNewGenerate, bool MustDopSelect) +``` + +### ConvertSimpleValueToQueryValueString + +__Назначение__: Конвертация константных значений в строки запроса + +__Параметры__: + +`value` - значение + +__Сигнатура__: + +```csharp +public virtual string ConvertSimpleValueToQueryValueString(object value) +``` + +### ConvertValueToQueryValueString + +__Назначение__: Конвертация значений в строки запроса + +__Параметры__: + +`value` - значение + +__Сигнатура__: + +```csharp +public virtual string ConvertValueToQueryValueString(object value) +``` + +### ConvertValueToQueryValueString + +__Назначение__: Преобразование значение свойства в строку для запроса + +__Параметры__: + +* `dataobject` - объект данных +* `propname` - имя свойства + +__Сигнатура__: + +```csharp +public virtual string ConvertValueToQueryValueString(DataObject dataobject, string propname) +``` + +### LimitFunction2SQLWhere + +__Назначение__: Преобразование функции + +__Параметры__:`LimitFunction` - настроечная структура выборки + +__Сигнатура__: + +```csharp +public virtual string LimitFunction2SQLWhere(STORMFunction LimitFunction, STORMDO.Business.StorageStructForView[] StorageStruct, string[] asnameprop, bool MustNewGenerate) +``` + +### LimitFunction2SQLWhere + +__Назначение__: Преобразование функции + +__Параметры__: + +`LimitFunction` - настроечная структура выборки + +__Сигнатура__: + +```csharp +public virtual string LimitFunction2SQLWhere(STORMFunction LimitFunction) +``` + +## Выполнение операций с указанием текста запроса + +### ReadFirst + +__Назначение__: Вычитка первой партии данных при [порционном чтении](fo_reading-portion.html). Кроме порции объектов данных, сервис данных возвращает состояние чтения `state`. Это состояние передается сервису данных для получения очередных порций (см. следующий метод).Выборка определяется текстом запроса. + +__Параметры__: + +* `Query` - Текст запроса для выборки данных +* `state` - Состояние вычитки(для последующей дочитки) +* `LoadingBufferSize` - размер порции + +__Сигнатура__: + +```csharp +public virtual object[][] ReadFirst(string Query, ref object State, int LoadingBufferSize) +``` + +### ReadNext + +__Назначение__: Получение очередной порции при [порционном чтении](fo_reading-portion.html). Должен предшествовать вызов предыдущего метода с получением состояния `state`. + +__Параметры__: + +* `state` - Состояние вычитки(для последующей дочитки) +* `LoadingBufferSize` - размер порции + +__Сигнатура__: + +```csharp +public virtual object[][] ReadNext(ref object State, int LoadingBufferSize) +``` + +### ExecuteNonQuery + +__Назначение__: Выполнить запрос + +__Параметры__: + +`Query` - текст SQL-запроса + +__Возвращаемый результат__: количество задетых строк + +__Сигнатура__: + +```csharp +public virtual int ExecuteNonQuery(string Query) +``` + +## Список событий для SQLDataService + +Кроме обработки указанных событий `SQLDataService` предоставляет возможность полного переопределения логики, т.к. содержит следующие делегаты: + +```csharp +// Делегат для события создания команды. +public delegate void OnCreateCommandEventHandler(object sender, CreateCommandEventArgs e); + +// Делегат для события при генерации SQL Select запроса (перед). +public delegate void OnGenerateSQLSelectEventHandler(object sender, GenerateSQLSelectQueryEventArgs e); + +// Делегат для события при генерации SQL Select запроса (после). +public delegate void AfterGenerateSQLSelectQueryEventHandler(object sender, GenerateSQLSelectQueryEventArgs e); + +// The before update objects event handler. +public delegate void BeforeUpdateObjectsEventHandler(object sender, DataObjectsEventArgs e); + +// The after update objects event handler. +public delegate void AfterUpdateObjectsEventHandler(object sender, DataObjectsEventArgs e); +``` + +|Событие|Описание| +|:------|:------ +| OnGenerateSQLSelect | Срабатывает перед генерацией SQL SELECT'а ([пример](fo_intercept-formation-sql-query.html)). Обрабатывая это событие можно, например, добавить дополнительные условия, которые должны попасть в формируемый запрос.| +| AfterGenerateSQLSelectQuery | Срабатывает после генерации SQL SELECT'а, но до вычитки данных ([пример](fo_intercept-formation-sql-query.html)). Можно использовать для внесения изменений в сгенерированный текст запроса.| +| BeforeUpdateObjects | Срабатывает перед обновлением объектов в базе, после отработки бизнес-серверов.| +| AfterUpdateObjects | Срабатывает после обновления объектов в базе.| +| OnCreateCommand | Срабатывает при создании SQL-команды ([пример](fo_intercept-formation-sql-query.html)).| + +### Задание CommandTimeout + +Есть возможность указывать [IDbCommand.CommandTimeout](http://msdn.microsoft.com/ru-ru/library/system.data.idbcommand.commandtimeout.aspx). Для этого можно в конфигурационном файле задать параметр: + +```xml + +``` + +либо присвоить значение явно: + +```csharp +IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. +IDataService ds = mainUnityContainer.Resolve(); +SQLDataService sqldataservice = (SQLDataService)ds; +sqldataservice.UseCommandTimeout = true; +sqldataservice.CommandTimeout = 60; +``` + +`UseCommandTimeout` нужно указывать обязательно. По-умолчанию этот флаг имеет значение `false`. + +Такая сложная реализация нужна для возможности включения-отключения использования уникальных значений без потери предыдущего значения таймаута. + +Также важно понимать, что при выполнении любой операции (чтение/обновление и т.д.) коннекция создаётся, а в конце закрывается. Т.е. последовательные LoadObjects будут выполнены в на разных `System.Data.IDbConnection`. + +Соответственно применяться настройка времени ожидания выполнения команды будет каждый раз заново. + +> Время ожидания выполнения команды *в секундах*. Значение по умолчанию — 30 секунд. + +### Смена строки соединения + +`SQLDataService` поддерживает возможность смены строки соединения. Такая возможность, в частности, используется для работы с несколькими БД в одном приложении, описание доступно в [статье](fo_multibase.html). diff --git a/pages/products/flexberry-orm/data-service/fo_sql-query.ru.md b/pages/products/flexberry-orm/data-service/fo_sql-query.ru.md index 6e25edaea..f727bd7e9 100644 --- a/pages/products/flexberry-orm/data-service/fo_sql-query.ru.md +++ b/pages/products/flexberry-orm/data-service/fo_sql-query.ru.md @@ -13,8 +13,8 @@ lang: ru В технологии Flexberry существуют следующие способы доступа к базе данных: * [Сервис данных](fo_data-service.html). Для чтения данных возможно использование как - * [Функции ограничения](fo_limit-function.html), - * так и [LINQProvider](fo_linq-provider.html)). + * [Функции ограничения](fo_limit-function.html), + * так и [LINQProvider](fo_linq-provider.html). * ADO.NET. Позволяет выполнять SQL-запросы из кода. __Примечание__: ADO.NET `НЕ ИСПОЛЬЗУЕТСЯ` в проектах в случаях, когда без него можно обойтись. Даже если возникла острая необходимость использовать ADO.NET, следует проверить, нельзя ли обойтись без него. Возможно, подойдет использование [funcSQL](fo_func-sql.html). @@ -25,7 +25,7 @@ lang: ru Из чего складывается текст SQL-запроса, генерируемого [сервисом данных](fo_data-service.html): -* Настройки [LoadingCustomizationStruct](fo_loading-customization-struct.html) (работу по сортировке, наложению [limitFunction](fo_limit-function.html), подчёту агрегирующих значений и прочим аналогичным действиям необходимо перекладывать на сервер за счёт задания параметров `LoadingCustomizationStruct`. +* Настройки [LoadingCustomizationStruct](fo_loading-customization-struct.html) (работу по сортировке, наложению [limitFunction](fo_limit-function.html), подчёту агрегирующих значений и прочим аналогичным действиям необходимо перекладывать на сервер за счёт задания параметров `LoadingCustomizationStruct`). * Атрибутивная разметка (например, атрибут `Storage` как классов, так и связей). * Реализация [Inheritance](fd_inheritance.html) с иcпользованием [TypeUsage](fo_type-usage-problem.html). * [Перехват запроса к БД](fo_intercept-formation-sql-query.html). @@ -40,21 +40,23 @@ lang: ru Ниже представлен пример исполнения SQL-запросов через технологию ADO.Net: ``` csharp -var connection = (SqlConnection)((SQLDataService)DataServiceProvider.DataService).GetConnection(); // Получение подключения. +IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. +IDataService ds = mainUnityContainer.Resolve(); +var connection = (SqlConnection)((SQLDataService)ds).GetConnection(); // Получение подключения. var command = new SqlCommand("SELECT SUM(purchase.\"Сумма\") "+ - " FROM \"Покупатель\" customer join \"Покупка\" purchase on customer.\"primaryKey\" = purchase.\"Покупатель\" "+ - " WHERE purchase.\"Покупатель\"=@Customer AND purchase.\"Статус\" = \'Оплачено\' ", connection); //формирование запроса + " FROM \"Покупатель\" customer join \"Покупка\" purchase on customer.\"primaryKey\" = purchase.\"Покупатель\" "+ + " WHERE purchase.\"Покупатель\"=@Customer AND purchase.\"Статус\" = \'Оплачено\' ", connection); //формирование запроса var parameter = new SqlParameter("@Customer", SqlDbType.UniqueIdentifier); parameter.Value = ((KeyGuid)this.__PrimaryKey).Guid; // Определение значения параметра. command.Parameters.Add(parameter); try { - connection.Open(); - var value = (decimal)command.ExecuteScalar(); // Исполнение запроса. + connection.Open(); + var value = (decimal)command.ExecuteScalar(); // Исполнение запроса. } finally { - connection.Close(); + connection.Close(); } ``` diff --git a/pages/products/flexberry-orm/data-types/fo_nonstored-calculated-properties.ru.md b/pages/products/flexberry-orm/data-types/fo_nonstored-calculated-properties.ru.md index a48a317c8..81eac7aca 100644 --- a/pages/products/flexberry-orm/data-types/fo_nonstored-calculated-properties.ru.md +++ b/pages/products/flexberry-orm/data-types/fo_nonstored-calculated-properties.ru.md @@ -1,45 +1,46 @@ ---- -title: Пример нехранимых свойств объектов -sidebar: flexberry-orm_sidebar -keywords: Flexberry ORM, типы данных -summary: Пример использования вычислимых свойств объектов -toc: true -permalink: ru/fo_nonstored-calculated-properties.html -lang: ru ---- - -В этом примере показывается, как использовать [вычислимые свойства](fo_not-stored-attributes.html). - -Пример определения вычислимого свойства для объекта `Person`: - -```csharp -[ICSSoft.STORMNET.NotStored()) -[StrLen(255)) -[DataServiceExpression(typeof(SQLDataService), "isnull(@FirstName@,\'\') + \' \' + isnull(@LastName@,\'\')")) -public virtual string FullName -{ - get - { - return string.Format("{0} {1}", fFirstName, fLastName); - } - set - { - } -} -``` - -В атрибуте `DataServiceExpression` определено выражение, которое будет использоваться [сервисом данных](fo_data-service.html) при выполнении запроса из таблицы. -Эквивалентный этому выражению код на C# написан в геттере свойства. - -```csharp -IDataService dataService = DataServiceProvider.DataService; -LoadingCustomizationStruct lcs = LoadingCustomizationStruct.GetSimpleStruct(typeof(Person), Person.Views.Person_E); - -// Загрузить все объекты данных. Нехранимое свойство будет вычислено с помощью выражения в геттере. -ICSSoft.STORMNET.DataObject[) persons = dataService.LoadObjects(lcs); - -// Загрузка в виде строкового представления, свойства отделены друг от друга точкой с запятой. Нехранимое свойство будет вычислено с помощью выражения в атрибуте DataServiceExpression. -ObjectStringDataView[) osdvpersons = dataService.LoadStringedObjectView(';', lcs); - -Console.WriteLine("OK."); -``` +--- +title: Пример нехранимых свойств объектов +sidebar: flexberry-orm_sidebar +keywords: Flexberry ORM, типы данных +summary: Пример использования вычислимых свойств объектов +toc: true +permalink: ru/fo_nonstored-calculated-properties.html +lang: ru +--- + +В этом примере показывается, как использовать [вычислимые свойства](fo_not-stored-attributes.html). + +Пример определения вычислимого свойства для объекта `Person`: + +```csharp +[ICSSoft.STORMNET.NotStored()) +[StrLen(255)) +[DataServiceExpression(typeof(SQLDataService), "isnull(@FirstName@,\'\') + \' \' + isnull(@LastName@,\'\')")) +public virtual string FullName +{ + get + { + return string.Format("{0} {1}", fFirstName, fLastName); + } + set + { + } +} +``` + +В атрибуте `DataServiceExpression` определено выражение, которое будет использоваться [сервисом данных](fo_data-service.html) при выполнении запроса из таблицы. +Эквивалентный этому выражению код на C# написан в геттере свойства. + +```csharp +IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. +IDataService ds = mainUnityContainer.Resolve(); +LoadingCustomizationStruct lcs = LoadingCustomizationStruct.GetSimpleStruct(typeof(Person), Person.Views.Person_E); + +// Загрузить все объекты данных. Нехранимое свойство будет вычислено с помощью выражения в геттере. +ICSSoft.STORMNET.DataObject[) persons = dataService.LoadObjects(lcs); + +// Загрузка в виде строкового представления, свойства отделены друг от друга точкой с запятой. Нехранимое свойство будет вычислено с помощью выражения в атрибуте DataServiceExpression. +ObjectStringDataView[) osdvpersons = ds.LoadStringedObjectView(';', lcs); + +Console.WriteLine("OK."); +``` diff --git a/pages/products/flexberry-orm/data-types/fo_using-custom-types-example.ru.md b/pages/products/flexberry-orm/data-types/fo_using-custom-types-example.ru.md index bbcdbb7b0..de88736fd 100644 --- a/pages/products/flexberry-orm/data-types/fo_using-custom-types-example.ru.md +++ b/pages/products/flexberry-orm/data-types/fo_using-custom-types-example.ru.md @@ -110,21 +110,22 @@ public virtual IIS.CDLIB.Dollar Price ### Пример загрузки и сохранения объекта с собственными типами ```csharp -IDataService dataService = DataServiceProvider.DataService; -OrmSample ormSample = new OrmSample(dataService); +IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. +IDataService ds = mainUnityContainer.Resolve(); +OrmSample ormSample = new OrmSample(ds); object primaryKey = ormSample.GetSomeObjectPrimaryKey(typeof(CDDA)); CDDA cdda = new CDDA(); cdda.SetExistObjectPrimaryKey(primaryKey); // Загрузка объекта из БД по представлению CD_E. -dataService.LoadObject(CD.Views.CD_E, cdda); +ds.LoadObject(CD.Views.CD_E, cdda); // Изменим цену. cdda.Price = new Dollar(0, 55); // Сохраним объект в БД. -dataService.UpdateObject(cdda); +ds.UpdateObject(cdda); Console.WriteLine(string.Format("'{0}' price is {1}", cdda.Name, cdda.Price)); ``` diff --git a/pages/products/flexberry-orm/dependency-injection/fo_ds-provider.ru.md b/pages/products/flexberry-orm/dependency-injection/fo_ds-provider.ru.md index a44f7b7a1..cc1d4cbef 100644 --- a/pages/products/flexberry-orm/dependency-injection/fo_ds-provider.ru.md +++ b/pages/products/flexberry-orm/dependency-injection/fo_ds-provider.ru.md @@ -1,80 +1,81 @@ ---- -title: Получение сервиса данных -sidebar: flexberry-orm_sidebar -keywords: Dataserviceprovider, DataService, connectionstring, config, app.config, web.config -summary: Как настроить сервис данных и получить его инстанцию из любого места приложения -toc: true -permalink: ru/fo_ds-provider.html -lang: ru ---- - -`DataServiceProvider.DataService` - это [сервис данных](fo_data-service.html), который инициализируется на основании параметров, заданных в файле конфигурации (`App.cobfig` или `Web.config`). Таким образом, `DataServiceProvider.DataService` является [сервисом данных](fo_data-service.html) по умолчанию. - -### Алгоритм инициализации DataServiceProvider.DataService - -При инициализации `DataServiceProvider.DataService` используется следующий алгоритм (инициализация происходит, если нет закэшированного значения, либо стоит флаг, что всегда нужно возвращать новый сервис данных): - -1.Производится попытка разрешить тип [сервиса данных](fo_data-service.html) через Unity. Например, чтобы использовался MSSQLDataService, в файле конфигурации требуется добавить следующее определение: - -```xml - - - -
- - - - - - - - - - -``` - -2.Если тип [сервиса данных](fo_data-service.html) удалось разрешить через Unity, то определяется строка соединения. Сначала в web-стиле, потом в win-стиле. - -**web-стиль**: - -```xml - - - - - - - - - -``` - -**win-стиль**: - -```xml - - - - - - -``` - - -3.Далее получение DataServiceProvider.DataService происходит по старому алгоритму. Тип [сервиса данных](fo_data-service.html) - через настройку DataServiceType в файле конфигурации. А строка соединения определяется в зависимости от того, в каком режиме приложение, web или win. - -```xml - - - - - - -``` - -## Строки соединения - -Подробнее почитать про строки подключения для LocalDB можно почитать в [этой статье](fd_sql-express-local-db.html). - -Про строки подключения в целом можно почитать в [msdn](https://msdn.microsoft.com/ru-ru/library/ms254500(v=vs.110).aspx). +--- +title: Получение сервиса данных +sidebar: flexberry-orm_sidebar +keywords: Dataserviceprovider, DataService, connectionstring, config, app.config, web.config +summary: Как настроить сервис данных и получить его инстанцию из любого места приложения +toc: true +permalink: ru/fo_ds-provider.html +lang: ru +--- +IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. +IDataService ds = mainUnityContainer.Resolve(); + +`IDataService` - это [сервис данных](fo_data-service.html), который инициализируется на основании параметров, заданных в файле конфигурации (`App.cobfig` или `Web.config`). Таким образом, `IDataService` является [сервисом данных](fo_data-service.html) по умолчанию. + +### Алгоритм инициализации IDataService + +При инициализации `IDataService` используется следующий алгоритм (инициализация происходит, если нет закэшированного значения, либо стоит флаг, что всегда нужно возвращать новый сервис данных): + +1.Производится попытка разрешить тип [сервиса данных](fo_data-service.html) через Unity. Например, чтобы использовался MSSQLDataService, в файле конфигурации требуется добавить следующее определение: + +```xml + + + +
+ + + + + + + + + + +``` + +2.Если тип [сервиса данных](fo_data-service.html) удалось разрешить через Unity, то определяется строка соединения. Сначала в web-стиле, потом в win-стиле. + +**web-стиль**: + +```xml + + + + + + + + + +``` + +**win-стиль**: + +```xml + + + + + + +``` + +3.Далее получение IDataService происходит по старому алгоритму. Тип [сервиса данных](fo_data-service.html) - через настройку DataServiceType в файле конфигурации. А строка соединения определяется в зависимости от того, в каком режиме приложение, web или win. + +```xml + + + + + + +``` + +## Строки соединения + +Подробнее почитать про строки подключения для LocalDB можно почитать в [этой статье](fd_sql-express-local-db.html). + +Про строки подключения в целом можно почитать в [msdn](https://msdn.microsoft.com/ru-ru/library/ms254500(v=vs.110).aspx). diff --git a/pages/products/flexberry-orm/lock-service/fo_lock-service.ru.md b/pages/products/flexberry-orm/lock-service/fo_lock-service.ru.md index d271ed4bd..0f93062d6 100644 --- a/pages/products/flexberry-orm/lock-service/fo_lock-service.ru.md +++ b/pages/products/flexberry-orm/lock-service/fo_lock-service.ru.md @@ -1,44 +1,44 @@ ---- -title: Сервис блокировок -sidebar: flexberry-orm_sidebar -keywords: Flexberry ORM, LockService -summary: Назначение и использование сервиса блокировок -toc: true -permalink: ru/fo_lock-service.html -lang: ru ---- - -Сервис блокировок (`ICSSoft.STORMNET.Business.LockService`) предназначен для удобной реализации механизма блокировок. Например, требуется защитить некоторый объект данных от изменения другими пользователями в то время, как он редактируется каким-либо пользователем. - -Для того чтобы выставить блокировку, требуется воспользоваться одним из методов `SetLock`. - -Для проверки блокировки следует пользоваться методом `GetLock`, либо попытаться повторно выполнить `SetLock`. Возвращённое непустое значение будет именем пользователя, который заблокировал объект. - -Для снятия блокировок необходимо пользоваться методом `ClearLock`. - -```csharp -Автор автор = new Автор(); -LockService ls = new LockService(); -ls.SetLock(автор); //Блокирование -string sLockID = ls.SetLock(автор); //Попытка повторного блокирования того же объекта -if (sLockID!=string.Empty) -{ - Console.WriteLine(string.Format("Заблокировано пользователем: {0}", sLockID)); -} -ls.ClearLock(автор);//Очистка блокировки -Console.ReadLine(); -``` - -Сервис блокировок обращается к хранилищу данных через [сервис данных](fo_data-service.html), указанный в [провайдере сервиса данных](fo_ds-provider.html) (`ICSSoft.STORMNET.Business.DataServiceProvider.DataService`). - -В хранилище для блокировок должен существовать соответствующий источник. - -Для реляционного хранения, он определён так: - -``` sql -SQL -CREATE TABLE STORMNETLOCKDATA ( - LockKey char (300) NOT NULL , - UserName char (300) NOT NULL -) -``` +--- +title: Сервис блокировок +sidebar: flexberry-orm_sidebar +keywords: Flexberry ORM, LockService +summary: Назначение и использование сервиса блокировок +toc: true +permalink: ru/fo_lock-service.html +lang: ru +--- + +Сервис блокировок (`ICSSoft.STORMNET.Business.LockService`) предназначен для удобной реализации механизма блокировок. Например, требуется защитить некоторый объект данных от изменения другими пользователями в то время, как он редактируется каким-либо пользователем. + +Для того чтобы выставить блокировку, требуется воспользоваться одним из методов `SetLock`. + +Для проверки блокировки следует пользоваться методом `GetLock`, либо попытаться повторно выполнить `SetLock`. Возвращённое непустое значение будет именем пользователя, который заблокировал объект. + +Для снятия блокировок необходимо пользоваться методом `ClearLock`. + +```csharp +Автор автор = new Автор(); +LockService ls = new LockService(); +ls.SetLock(автор); //Блокирование +string sLockID = ls.SetLock(автор); //Попытка повторного блокирования того же объекта +if (sLockID!=string.Empty) +{ + Console.WriteLine(string.Format("Заблокировано пользователем: {0}", sLockID)); +} +ls.ClearLock(автор);//Очистка блокировки +Console.ReadLine(); +``` + +Сервис блокировок обращается к хранилищу данных через [сервис данных](fo_data-service.html), указанный в [провайдере сервиса данных](fo_ds-provider.html) (`ICSSoft.STORMNET.Business.IDataService`). + +В хранилище для блокировок должен существовать соответствующий источник. + +Для реляционного хранения, он определён так: + +``` sql +SQL +CREATE TABLE STORMNETLOCKDATA ( + LockKey char (300) NOT NULL , + UserName char (300) NOT NULL +) +``` diff --git a/pages/products/flexberry-orm/odata-service/fo_orm-odata-service.en.md b/pages/products/flexberry-orm/odata-service/fo_orm-odata-service.en.md index 58d201e7b..36ad7b75f 100644 --- a/pages/products/flexberry-orm/odata-service/fo_orm-odata-service.en.md +++ b/pages/products/flexberry-orm/odata-service/fo_orm-odata-service.en.md @@ -97,7 +97,7 @@ namespace ODataServiceTemplate } ``` - * In The Global.asax, add: +* In The Global.asax, add: ```csharp namespace ODataServiceTemplate @@ -122,9 +122,9 @@ namespace ODataServiceTemplate } ``` - * In order for code to compile, you may need to install additional NuGet packages in the app: [Microsoft.AspNet.WebApi.Cors](https://www.nuget.org/packages/Microsoft.AspNet.WebApi.Cors) and [microsoft.aspnet.webapi.webhost](https://www.nuget.org/packages/microsoft.aspnet.webapi.webhost/). +* In order for code to compile, you may need to install additional NuGet packages in the app: [Microsoft.AspNet.WebApi.Cors](https://www.nuget.org/packages/Microsoft.AspNet.WebApi.Cors) and [microsoft.aspnet.webapi.webhost](https://www.nuget.org/packages/microsoft.aspnet.webapi.webhost/). - * Add to web.config or to check the availability of the following records: +* Add to web.config or to check the availability of the following records: ```xml diff --git a/pages/products/flexberry-orm/odata-service/fo_orm-odata-service.ru.md b/pages/products/flexberry-orm/odata-service/fo_orm-odata-service.ru.md index dbb25cdcc..feb9768e5 100644 --- a/pages/products/flexberry-orm/odata-service/fo_orm-odata-service.ru.md +++ b/pages/products/flexberry-orm/odata-service/fo_orm-odata-service.ru.md @@ -45,9 +45,9 @@ ODataService представляет собой WebApi-контроллер, к * В E-представление (представление, имеющее название "<ИмяКласса>E") детейла должна быть добавлена ссылка на агрегатор. * Подключение `Flexberry ORM ODataService`. Для подключения в web-проект (WebForms) воспользоваться возможностями `Flexberry ORM ODataService`, необходимо сделать следующее: - * Подключить NuGet-пакет `Flexberry ORM ODataService`. - * В App_Start приложения создать класс "ODataConfig.cs". - * Заменить содержимое класса примерно на следующее: + * Подключить NuGet-пакет `Flexberry ORM ODataService`. + * В App_Start приложения создать класс "ODataConfig.cs". + * Заменить содержимое класса примерно на следующее: ```csharp namespace ODataServiceTemplate @@ -95,7 +95,7 @@ namespace ODataServiceTemplate } ``` - * В Global.asax добавить: +* В Global.asax добавить: ```csharp namespace ODataServiceTemplate @@ -120,9 +120,9 @@ namespace ODataServiceTemplate } ``` - * Для того, чтобы код компилировался, может потребоваться установить дополнительно NuGet-пакеты в приложение: [Microsoft.AspNet.WebApi.Cors](https://www.nuget.org/packages/Microsoft.AspNet.WebApi.Cors) и [microsoft.aspnet.webapi.webhost](https://www.nuget.org/packages/microsoft.aspnet.webapi.webhost/). +* Для того, чтобы код компилировался, может потребоваться установить дополнительно NuGet-пакеты в приложение: [Microsoft.AspNet.WebApi.Cors](https://www.nuget.org/packages/Microsoft.AspNet.WebApi.Cors) и [microsoft.aspnet.webapi.webhost](https://www.nuget.org/packages/microsoft.aspnet.webapi.webhost/). - * Добавить в web.config или проверить наличие следующих записей: +* Добавить в web.config или проверить наличие следующих записей: ```xml @@ -225,7 +225,9 @@ public static void Register(HttpConfiguration config) config.DependencyResolver = new UnityDependencyResolver(container); // Самое главное для ODataService - знать какой сервис данных используется. Можно зарегистрировать тут или в web.config в секции Unity. - container.RegisterInstance(DataServiceProvider.DataService); + IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. + IDataService ds = mainUnityContainer.Resolve(); + container.RegisterInstance(ds); try { @@ -261,7 +263,9 @@ public static void Register(HttpConfiguration config) /// private static object GetLastRoundIdForTopic(ODataFunctions.QueryParameters queryParameters, Dictionary parameters) { - ApplicationLogicBS bs = new ApplicationLogicBS { DataService = DataServiceProvider.DataService }; + IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. + IDataService ds = mainUnityContainer.Resolve(); + ApplicationLogicBS bs = new ApplicationLogicBS { DataService = ds }; return bs.GetLastRoundIdForTopic((string)parameters["topicId"]); } ``` @@ -471,7 +475,9 @@ public static void Register(HttpConfiguration config, IUnityContainer container, /// private static IEnumerable FunctionWithLcs1(QueryParameters queryParameters, string entitySet) { - SQLDataService dataService = DataServiceProvider.DataService as SQLDataService; + IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. + IDataService ds = mainUnityContainer.Resolve(); + SQLDataService dataService = ds as SQLDataService; var type = queryParameters.GetDataObjectType(entitySet); var lcs = queryParameters.CreateLcs(type); var dobjs = dataService.LoadObjects(lcs); @@ -487,7 +493,9 @@ private static IEnumerable FunctionWithLcs1(QueryParameters queryPar /// private static int FunctionWithLcs2(QueryParameters queryParameters, string entitySet, string query) { - SQLDataService dataService = DataServiceProvider.DataService as SQLDataService; + IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. + IDataService ds = mainUnityContainer.Resolve(); + SQLDataService dataService = ds as SQLDataService; var type = queryParameters.GetDataObjectType(entitySet); var uri = $"http://a/b/c?{query}"; var lcs = queryParameters.CreateLcs(type, uri); @@ -540,7 +548,9 @@ public static void Register(HttpConfiguration config, IUnityContainer container, /// private static IEnumerable ActionWithLcs(QueryParameters queryParameters, string entitySet, string query) { - SQLDataService dataService = DataServiceProvider.DataService as SQLDataService; + IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. + IDataService ds = mainUnityContainer.Resolve(); + SQLDataService dataService = ds as SQLDataService; var type = queryParameters.GetDataObjectType(entitySet); var uri = $"http://a/b/c?{query}"; var lcs = queryParameters.CreateLcs(type, uri); @@ -554,8 +564,10 @@ private static IEnumerable ActionWithLcs(QueryParameters queryParame Пример использования пользовательских функций для экспорта в Excel. Пример запроса: + +```html http://localhost/odata/FunctionExportExcel(entitySet='Странаs')?exportExcel=true&colsOrder=Название/Название&detSeparateCols=false&detSeparateRows=false&$filter=contains(Название,'1') -. +``` ```csharp /// @@ -596,7 +608,9 @@ public static void Register(HttpConfiguration config, IUnityContainer container, /// private static Страна[] FunctionExportExcel(QueryParameters queryParameters, string entitySet) { - SQLDataService dataService = DataServiceProvider.DataService as SQLDataService; + IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. + IDataService ds = mainUnityContainer.Resolve(); + SQLDataService dataService = ds as SQLDataService; Type type = queryParameters.GetDataObjectType(entitySet); LoadingCustomizationStruct lcs = queryParameters.CreateLcs(type); Страна[] dobjs = dataService.LoadObjects(lcs).Cast<Страна>().ToArray(); diff --git a/pages/products/flexberry-orm/query-language/fo_exist-details.ru.md b/pages/products/flexberry-orm/query-language/fo_exist-details.ru.md index c2a007ca8..0445edbbf 100644 --- a/pages/products/flexberry-orm/query-language/fo_exist-details.ru.md +++ b/pages/products/flexberry-orm/query-language/fo_exist-details.ru.md @@ -22,14 +22,16 @@ lang: ru ## Пример использования -![](/images/pages/products/flexberry-orm/query-language/exist-detals-example-2.jpg) +![exist-detals-example-2](/images/pages/products/flexberry-orm/query-language/exist-detals-example-2.jpg) В следующем коде подразумевается, что в представлении `"СерверПодразделенияE"` обязательно присутствуют свойства `"Подразделение"` (так как оно есть в условии) и `"Сервер"` (свойство, по которому идет соединение). Требуется вычитать те сервера, которые принадлежат определённому Подразделению (т.е. сервера, которые принадлежат и указанному Подразделению и еще какому-то, также будут вычитаны). ```csharp -ExternalLangDef ldef = ExternalLangDef.LanguageDef; +IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. +IDataService ds = mainUnityContainer.Resolve(); +ExternalLangDef languageDef = new ExternalLangDef(ds); LoadingCustomizationStruct lcsСервер = LoadingCustomizationStruct.GetSimpleStruct(typeof (Репликации.Сервер), "СерверE"); lcsСервер.LoadingTypes = new Type[] {typeof (Репликации.Сервер)}; View view = Information.GetView("СерверПодразделенияE", typeof(Репликации.СерверПодразделения)); @@ -37,20 +39,22 @@ ICSSoft.STORMNET.Windows.Forms.DetailVariableDef dvd = new ICSSoft.STORMNET.Wind dvd.ConnectMasterPorp = "Сервер"; dvd.OwnerConnectProp = new string[] { SQLWhereLanguageDef.StormMainObjectKey }; dvd.View = view; -dvd.Type = ldef.GetObjectType("Details"); -lcsСервер.LimitFunction = ldef.GetFunction(ldef.funcExist, +dvd.Type = languageDef.GetObjectType("Details"); +lcsСервер.LimitFunction = languageDef.GetFunction(languageDef.funcExist, dvd, - ldef.GetFunction(ldef.funcEQ, - new VariableDef(ldef.GuidType, "Подразделение"), + languageDef.GetFunction(languageDef.funcEQ, + new VariableDef(languageDef.GuidType, "Подразделение"), UpdatedObject.НаправленоИз.__PrimaryKey)); lcsСервер.ReturnTop = 1; -ICSSoft.STORMNET.DataObject[] dobjsСервер = ICSSoft.STORMNET.Business.DataServiceProvider.DataService.LoadObjects(lcsСервер); +ICSSoft.STORMNET.DataObject[] dobjsСервер = ICSSoft.STORMNET.Business.ds.LoadObjects(lcsСервер); ``` Требуется вычитать только те сервера, которые принадлежат только одному конкретному Подразделению (т.е. сервера, которые принадлежат и указанному Подразделению и еще какому-то, не будут вычитаны). ```csharp -ExternalLangDef ldef = ICSSoft.STORMNET.Windows.Forms.ExternalLangDef.LanguageDef; +IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. +IDataService ds = mainUnityContainer.Resolve(); +ExternalLangDef languageDef = new ExternalLangDef(ds); LoadingCustomizationStruct lcsСервер = LoadingCustomizationStruct.GetSimpleStruct(typeof (Сервер), "СерверE"); lcsСервер.LoadingTypes = new[] {typeof (Сервер)}; View view = Information.GetView("СерверПодразделенияE", typeof(Репликации.СерверПодразделения)); @@ -59,14 +63,14 @@ var dvd = new ICSSoft.STORMNET.Windows.Forms.DetailVariableDef ConnectMasterPorp = "Сервер", OwnerConnectProp = new[] { SQLWhereLanguageDef.StormMainObjectKey }, View = view, - Type = ldef.GetObjectType("Details") + Type = languageDef.GetObjectType("Details") }; -lcsСервер.LimitFunction = ldef.GetFunction(ldef.funcExistExact, +lcsСервер.LimitFunction = languageDef.GetFunction(languageDef.funcExistExact, dvd, - ldef.GetFunction(ldef.funcEQ, - new VariableDef(ldef.GuidType, "Подразделение"), + languageDef.GetFunction(languageDef.funcEQ, + new VariableDef(languageDef.GuidType, "Подразделение"), new Guid("6D7DC426-F5E9-4F63-B7B5-20C9E237DF2D"))); -DataObject[] dobjsСервер = DataServiceProvider.DataService.LoadObjects(lcsСервер); +DataObject[] dobjsСервер = ds.LoadObjects(lcsСервер); ``` ## Сравнения свойств двух различных детейлов (не выше первого уровня) имеющих общий агрегатор @@ -81,12 +85,14 @@ DataObject[] dobjsСервер = DataServiceProvider.DataService.LoadObjects(lcs view.AddDetailInView("Computer", view2, true); view.AddDetailInView("Computer", view3, true); var lcs = LoadingCustomizationStruct.GetSimpleStruct(typeof(Computer), view); - ExternalLangDef langDef = ExternalLangDef.LanguageDef; - var detail1 = new DetailVariableDef(langDef.GetObjectType("Details"), "Hardware", view2, "Computer"); - var detail2 = new DetailVariableDef(langDef.GetObjectType("Details"), "Software", view3, "Computer"); - lcs.LimitFunction = langDef.GetFunction(langDef.funcExistDetails, - detail1, detail2, langDef.GetFunction(langDef.funcG, - new VariableDef(langDef.DateTimeType, "DeliveryDate"), - new VariableDef(langDef.DateTimeType, "DeliveryDate"))); - var dos = DataServiceProvider.DataService.LoadObjects(lcs); +IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. +IDataService ds = mainUnityContainer.Resolve(); +ExternalLangDef languageDef = new ExternalLangDef(ds); + var detail1 = new DetailVariableDef(languageDef.GetObjectType("Details"), "Hardware", view2, "Computer"); + var detail2 = new DetailVariableDef(languageDef.GetObjectType("Details"), "Software", view3, "Computer"); + lcs.LimitFunction = languageDef.GetFunction(languageDef.funcExistDetails, + detail1, detail2, languageDef.GetFunction(languageDef.funcG, + new VariableDef(languageDef.DateTimeType, "DeliveryDate"), + new VariableDef(languageDef.DateTimeType, "DeliveryDate"))); + var dos = ds.LoadObjects(lcs); ``` diff --git a/pages/products/flexberry-orm/query-language/fo_func-to-char.ru.md b/pages/products/flexberry-orm/query-language/fo_func-to-char.ru.md index 97d689bd1..51f144358 100644 --- a/pages/products/flexberry-orm/query-language/fo_func-to-char.ru.md +++ b/pages/products/flexberry-orm/query-language/fo_func-to-char.ru.md @@ -1,43 +1,43 @@ ---- -title: FuncToChar -sidebar: flexberry-orm_sidebar -keywords: DateTime, Flexberry ORM, Ограничения -summary: Параметры и пример использования функции FuncToChar -toc: true -permalink: ru/fo_func-to-char.html -lang: ru ---- - -`FuncToChar` - функция из [ExternalLangDef](fo_external-lang-def.html), служащая для того, чтобы задать преобразование выражения в строку. Это бывает необходимо для корректного сравнения значений выражений со строковыми константами. На данный момент реализована только для [MSSQLDataService](fo_mssql-data-service.html) и [OracleDataService](fo_oracle-data-service.html). - -## Использование - -Функция может использоваться в двух вариантах: - -* С двумя аргументами, где первый - какое-либо выражение, возвращающее значение, а второй - число, означающее длину результирующей строки. -* С тремя аргументами, где первый - выражение, имеющее тип `DATETIME`, второй - длина строки, а третий - номер формата для отображения даты. Для задания последнего параметра можно использовать перечисление `ExternalLangDef.DateFormats`. В нем определены следующие значения: - - * `German` (DD.MM.YY) - * `GermanWithCentury` (DD.MM.YYYY) - * `Month` (DD Mon YY - сокращенное название месяца) - * `MonthWithCentury` (DD Mon YYYY) - * `Time` (hh:mi:ss - время) - -Кроме этого, можно использовать, другие форматы, задавая их числом. Полный список находится [здесь](http://msdn.microsoft.com/ru-ru/library/ms187928.aspx) (это возможно только для [MSSQLDataService](fo_mssql-data-service.html). - -### Пример использования - -Получение выражения, приводящего дату к строке и сравнение с помощью функции LIKE - -```csharp -var stringDate = _langdef.GetFunction( - _langdef.funcToChar, - new VariableDef(_langdef.DateTimeType, propertyName), - 10, // Длина строки, содержащей дату в формате 'DD.MM.YYYY' - ExternalLangDef.DateFormats.GermanWithCentury); - -return _langdef.GetFunction( - _langdef.funcLike, - stringDate, - string.Format("%{0}%", searchValue.Trim().ToLower())); -``` +--- +title: FuncToChar +sidebar: flexberry-orm_sidebar +keywords: DateTime, Flexberry ORM, Ограничения +summary: Параметры и пример использования функции FuncToChar +toc: true +permalink: ru/fo_func-to-char.html +lang: ru +--- + +`FuncToChar` - функция из [ExternalLangDef](fo_external-lang-def.html), служащая для того, чтобы задать преобразование выражения в строку. Это бывает необходимо для корректного сравнения значений выражений со строковыми константами. На данный момент реализована только для [MSSQLDataService](fo_mssql-data-service.html) и [OracleDataService](fo_oracle-data-service.html). + +## Использование + +Функция может использоваться в двух вариантах: + +* С двумя аргументами, где первый - какое-либо выражение, возвращающее значение, а второй - число, означающее длину результирующей строки. +* С тремя аргументами, где первый - выражение, имеющее тип `DATETIME`, второй - длина строки, а третий - номер формата для отображения даты. Для задания последнего параметра можно использовать перечисление `ExternalLangDef.DateFormats`. В нем определены следующие значения: + + * `German` (DD.MM.YY) + * `GermanWithCentury` (DD.MM.YYYY) + * `Month` (DD Mon YY - сокращенное название месяца) + * `MonthWithCentury` (DD Mon YYYY) + * `Time` (hh:mi:ss - время) + +Кроме этого, можно использовать, другие форматы, задавая их числом. Полный список находится [здесь](http://msdn.microsoft.com/ru-ru/library/ms187928.aspx) (это возможно только для [MSSQLDataService](fo_mssql-data-service.html). + +### Пример использования + +Получение выражения, приводящего дату к строке и сравнение с помощью функции LIKE + +```csharp +var stringDate = _langdef.GetFunction( + _langdef.funcToChar, + new VariableDef(_langdef.DateTimeType, propertyName), + 10, // Длина строки, содержащей дату в формате 'DD.MM.YYYY' + ExternalLangDef.DateFormats.GermanWithCentury); + +return _langdef.GetFunction( + _langdef.funcLike, + stringDate, + string.Format("%{0}%", searchValue.Trim().ToLower())); +``` diff --git a/pages/products/flexberry-orm/query-language/fo_function-builder.ru.md b/pages/products/flexberry-orm/query-language/fo_function-builder.ru.md index 4242771fe..6d10627c2 100644 --- a/pages/products/flexberry-orm/query-language/fo_function-builder.ru.md +++ b/pages/products/flexberry-orm/query-language/fo_function-builder.ru.md @@ -17,9 +17,10 @@ lang: ru `FunctionBuilder` поддерживает не все множество функций, доступных для использования в `GetFunction`, однако большую его часть, что позволяет прикладному разработчику использовать его для построения функций ограничения в большинстве ситуаций, тем самым уменьшая громоздскость кода. При необходимости можно реализовать дополнительные методы FunctionBuilder по аналогии с уже реализованными. ## Пример + Представим себе модель данных, в которой есть сущность Документ (Document) и сущность СвязьДокументов (DocumentLink), имеющая две ссылки на Документ с наименованиями Document и LinkedDocument, а также ссылку на объект ТипСвязиДокументов (DocumentLinkType). -![](/images/pages/products/flexberry-orm/query-language/function-builder-example-model.png) +![Пример](/images/pages/products/flexberry-orm/query-language/function-builder-example-model.png) Предположим, нам необходимо вычитать из БД все объекты DocumentLink с определенным наименованием типа связи, связывающие два документа, и при этом не учитывать порядок, в котором фигурируют заданные документы в объекте СвязьДокументов. Таким образом мы должны получить ограничение, примерно соответствующее следующему sql-запросу: @@ -32,6 +33,7 @@ AND ((Document = @document1 AND LinkedDocument = @document2) OR (Document = @doc ``` ### Функция ограничения с использованием langdef + ```csharp var lcs = LoadingCustomizationStruct.GetSimpleStruct(typeof(DocumentLink), DocumentLink.Views.DocumentLinkE); lcs.LimitFunction = langdef.GetFunction(langdef.funcAND, @@ -46,6 +48,7 @@ lcs.LimitFunction = langdef.GetFunction(langdef.funcAND, ``` ### Функция ограничения с использованием FunctionBuilder + ``` csharp var lcs = LoadingCustomizationStruct.GetSimpleStruct(typeof(DocumentLink), DocumentLink.Views.DocumentLinkE); lcs.LimitFunction = FunctionBuilder.BuildAnd( @@ -66,9 +69,9 @@ lcs.LimitFunction = FunctionBuilder.BuildAnd( Как можно видеть из примера, код построения функции с использованием FunctionBuilder очень похож, но становится читаемее за счет меньшего количества аргументов у методов, а также отсутствия необходимости создавать VariableDef вручную в большинстве случаев. Кроме того, в примере с `FunctionBuilder-ом` нельзя допустить ошибку в пути свойства, поскольку используется generic-метод, контролирующий имеющиеся в объекте свойства. Аналогичный по возможностям код можно реализовать и в случае использования `GetFunction` с использованием метода `Information.ExtractPropertyPath()`, однако это сделает код еще многословнее. ## Исходный код + С исходным кодом `FunctionBuilder` и вспомогательных классов можно ознакомиться в [репозитории ORM](https://github.com/Flexberry/NewPlatform.Flexberry.ORM/tree/develop/ExternalLangDef/FunctionBuilder). Все методы покрыты тестовыми сценариями, с кодом которых также можно ознакомиться в [репозитории ORM](https://github.com/Flexberry/NewPlatform.Flexberry.ORM/tree/develop/NewPlatform.Flexberry.ORM.Tests/ICSSoft.STORMNET.FunctionalLanguage). ## Методы, доступные в FunctionBuilder Список методов, перечисленных здесь, может со временем измениться, поэтому за полным списком возможностей рекомендуется обратиться к [автодокументации](https://flexberry.github.io/NewPlatform.Flexberry.ORM/autodoc/develop/class_i_c_s_soft_1_1_s_t_o_r_m_n_e_t_1_1_functional_language_1_1_function_builder.html). - diff --git a/pages/products/flexberry-orm/query-language/fo_function-implication.en.md b/pages/products/flexberry-orm/query-language/fo_function-implication.en.md index 9fdcd6153..18b681daa 100644 --- a/pages/products/flexberry-orm/query-language/fo_function-implication.en.md +++ b/pages/products/flexberry-orm/query-language/fo_function-implication.en.md @@ -14,12 +14,12 @@ hash: 14f3ec1abd5d086284697d694c1fb658c2f1fe7fed54b324cf1df98b5625d1cb The implication is a function that takes two logical operands: antecedents and consequences, can take the following values: -Prerequisite | Consequence | Result -:----------|:----------|:---------- -0 | 0 | 1 -0 | 1 | 1 -1 | 0 | 0 -1 | 1 | 1 +Prerequisite | Consequence | Result +:----------|:----------|:---------- +0 | 0 | 1 +0 | 1 | 1 +1 | 0 | 0 +1 | 1 | 1 Logically, the implication "If a, then b" is equal to "(not a) or b". For example, a constraint of the form: "If nickname = snow leopard, then gender = male" would lead to the conclusion all cats with the male sex and all (not snow leopard). diff --git a/pages/products/flexberry-orm/query-language/fo_function-implication.ru.md b/pages/products/flexberry-orm/query-language/fo_function-implication.ru.md index 12cc4e811..68e212994 100644 --- a/pages/products/flexberry-orm/query-language/fo_function-implication.ru.md +++ b/pages/products/flexberry-orm/query-language/fo_function-implication.ru.md @@ -1,35 +1,34 @@ ---- -title: Функция импликации -sidebar: flexberry-orm_sidebar -keywords: Flexberry ORM, ограничения, импликация? funcImplication -summary: Использование импликации в ограничениях -toc: true -permalink: ru/fo_function-implication.html -lang: ru ---- - -`funcImplication` - функция [ExternalLangDef](fo_external-lang-def.html) для задания логической импликации. - -Импликация - функция двух логических операндов: предпосылки и следствия, может принимать следующие значения: - -Предпосылка | Следствие | Результат -:----------|:----------|:---------- - 0 | 0 | 1 - 0 | 1 | 1 - 1 | 0 | 0 - 1 | 1 | 1 - -Логически, импликация "Если а, то b " равна "(не a) или b". -Например, ограничение вида: "Если кличка = барсик, то пол = мужской" приведет к выводу всех барсиков с мужским полом и всех (не барсиков). - - -## Пример - -**Все Ивановы Иваны и все не Ивановы** - -``` csharp -var langDef = new ExternalLangDef(); -Function function = langDef.GetFunction(langDef.funcImplication, - langDef.GetFunction(langDef.funcEQ, new VariableDef(langDef.StringType, "Фамилия"),"Иванов"), - langDef.GetFunction(langDef.funcEQ, new VariableDef(langDef.StringType, "Имя"), "Иван")); -``` +--- +title: Функция импликации +sidebar: flexberry-orm_sidebar +keywords: Flexberry ORM, ограничения, импликация? funcImplication +summary: Использование импликации в ограничениях +toc: true +permalink: ru/fo_function-implication.html +lang: ru +--- + +`funcImplication` - функция [ExternalLangDef](fo_external-lang-def.html) для задания логической импликации. + +Импликация - функция двух логических операндов: предпосылки и следствия, может принимать следующие значения: + +Предпосылка | Следствие | Результат +:----------|:----------|:---------- + 0 | 0 | 1 + 0 | 1 | 1 + 1 | 0 | 0 + 1 | 1 | 1 + +Логически, импликация "Если а, то b " равна "(не a) или b". +Например, ограничение вида: "Если кличка = барсик, то пол = мужской" приведет к выводу всех барсиков с мужским полом и всех (не барсиков). + +## Пример + +Для иллюстрации будет использовано утверждение __Все Ивановы Иваны и все не Ивановы__. + +``` csharp +var langDef = new ExternalLangDef(); +Function function = langDef.GetFunction(langDef.funcImplication, + langDef.GetFunction(langDef.funcEQ, new VariableDef(langDef.StringType, "Фамилия"),"Иванов"), + langDef.GetFunction(langDef.funcEQ, new VariableDef(langDef.StringType, "Имя"), "Иван")); +``` diff --git a/pages/products/flexberry-orm/query-language/fo_function-list.ru.md b/pages/products/flexberry-orm/query-language/fo_function-list.ru.md index 5cb7d1f36..d85f06a78 100644 --- a/pages/products/flexberry-orm/query-language/fo_function-list.ru.md +++ b/pages/products/flexberry-orm/query-language/fo_function-list.ru.md @@ -31,12 +31,12 @@ using ICSSoft.STORMNET.FunctionalLanguage.SQLWhere; ## Наложение ограничений на перечислимый тип -[Enumerations|Перечислимые типы) хранятся в базе как строки. Соответственно, при конструировании описания переменной ([VariableDef](fo_variable-def.html)) необходимо использовать `StringType`. В качестве аргумента для сравнения рекомендуется использовать `Caption` объекта перечисления, получить `Caption` можно при помощи класса `EnumCaption`, который является частью `ICSSoft.STORMNET`. +[Перечислимые типы](fd_enumerations.html) хранятся в базе как строки. Соответственно, при конструировании описания переменной ([VariableDef](fo_variable-def.html)) необходимо использовать `StringType`. В качестве аргумента для сравнения рекомендуется использовать `Caption` объекта перечисления, получить `Caption` можно при помощи класса `EnumCaption`, который является частью `ICSSoft.STORMNET`. Например: -![](/images/pages/products/flexberry-orm/query-language/Pol.PNG) - +![Pol](/images/pages/products/flexberry-orm/query-language/Pol.PNG) + Чтобы наложить ограничение на пол клиента, необходимо составить следующую функцию: ```csharp @@ -53,30 +53,32 @@ var onlyMenFunction = ld.GetFunction(ld.funcEQ, new VariableDef(ld.StringType, I ### Пример ```csharp -//ICSSoft.STORMNET.Windows.Forms.ExternalLangDef (ExternalLangDef.dll) -//ICSSoft.STORMNET.Windows.Forms.ExternalLangDeflangdef = ExternalLangDef.LanguageDef; + using ICSSoft.STORMNET.Windows.Forms; -var langdef = ExternalLangDef.LanguageDef; +IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. +IDataService ds = mainUnityContainer.Resolve(); +ExternalLangDef languageDef = new ExternalLangDef(ds); + var lcs = LoadingCustomizationStruct.GetSimpleStruct(typeof (Кредит), Кредит.Views.КредитE); -lcs.LimitFunction = langdef.GetFunction(langdef.funcEQ, - langdef.GetFunction("YearPart", new VariableDef(langdef.DateTimeType, "ДатаВыдачи")), "2013"); +lcs.LimitFunction = languageDef.GetFunction(languageDef.funcEQ, + languageDef.GetFunction("YearPart", new VariableDef(languageDef.DateTimeType, "ДатаВыдачи")), "2013"); -var only2013year = DataServiceProvider.DataService.LoadObjects(lcs); +var only2013year = ds.LoadObjects(lcs); -lcs.LimitFunction = langdef.GetFunction(langdef.funcEQ, - langdef.GetFunction("MonthPart", new VariableDef(langdef.DateTimeType, "ДатаВыдачи")), "12"); +lcs.LimitFunction = languageDef.GetFunction(languageDef.funcEQ, + languageDef.GetFunction("MonthPart", new VariableDef(languageDef.DateTimeType, "ДатаВыдачи")), "12"); -var onlyDecember = DataServiceProvider.DataService.LoadObjects(lcs); +var onlyDecember = ds.LoadObjects(lcs); -lcs.LimitFunction = langdef.GetFunction(langdef.funcAND, - langdef.GetFunction(langdef.funcEQ, - langdef.GetFunction("YearPart", new VariableDef(langdef.DateTimeType, "ДатаВыдачи")), "2012"), - langdef.GetFunction(langdef.funcEQ, - langdef.GetFunction("MonthPart", new VariableDef(langdef.DateTimeType, "ДатаВыдачи")), "12")); +lcs.LimitFunction = languageDef.GetFunction(languageDef.funcAND, + languageDef.GetFunction(languageDef.funcEQ, + languageDef.GetFunction("YearPart", new VariableDef(languageDef.DateTimeType, "ДатаВыдачи")), "2012"), + languageDef.GetFunction(languageDef.funcEQ, + languageDef.GetFunction("MonthPart", new VariableDef(languageDef.DateTimeType, "ДатаВыдачи")), "12")); -var onlyDecember2012 = DataServiceProvider.DataService.LoadObjects(lcs); +var onlyDecember2012 = ds.LoadObjects(lcs); ``` ## Примеры использования @@ -86,34 +88,42 @@ var onlyDecember2012 = DataServiceProvider.DataService.LoadObjects(lcs); ### Наложение ограничений на строковую переменную ```csharp -var langdef = ExternalLangDef.LanguageDef; +IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. +IDataService ds = mainUnityContainer.Resolve(); +ExternalLangDef languageDef = new ExternalLangDef(ds); var lcs = LoadingCustomizationStruct.GetSimpleStruct(typeof (Личность), Личность.Views.ЛичностьE); -lcs.LimitFunction = langdef.GetFunction(langdef.funcEQ, - new VariableDef(langdef.StringType, Information.ExtractPropertyPath<Личность>(x => x.Фамилия)), "Петров"); -var клиентыФамилияПетров = DataServiceProvider.DataService.LoadObjects(lcs); +lcs.LimitFunction = languageDef.GetFunction(languageDef.funcEQ, + new VariableDef(languageDef.StringType, Information.ExtractPropertyPath<Личность>(x => x.Фамилия)), "Петров"); +var клиентыФамилияПетров = ds.LoadObjects(lcs); ``` ### Наложение ограничений на мастеровой объект (по ключу) ```csharp -var langdef = ExternalLangDef.LanguageDef; +IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. +IDataService ds = mainUnityContainer.Resolve(); +ExternalLangDef languageDef = new ExternalLangDef(ds); + var lcs = LoadingCustomizationStruct.GetSimpleStruct(typeof (Кредит), Кредит.Views.КредитE); -lcs.LimitFunction = langdef.GetFunction(langdef.funcEQ, - new VariableDef(langdef.GuidType, Information.ExtractPropertyPath<Кредит>(x => x.Личность)), "64F45BC3-339B-4FBA-A036-C5E9FE9EAE53"); -var кредиты = DataServiceProvider.DataService.LoadObjects(lcs); +lcs.LimitFunction = languageDef.GetFunction(languageDef.funcEQ, + new VariableDef(languageDef.GuidType, Information.ExtractPropertyPath<Кредит>(x => x.Личность)), "64F45BC3-339B-4FBA-A036-C5E9FE9EAE53"); +var кредиты = ds.LoadObjects(lcs); ``` ### Наложение ограничений на мастеровой объект (по полю мастера) ```csharp -var langdef = ExternalLangDef.LanguageDef; +IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. +IDataService ds = mainUnityContainer.Resolve(); +ExternalLangDef languageDef = new ExternalLangDef(ds); + var lcs = LoadingCustomizationStruct.GetSimpleStruct(typeof (Кредит), Кредит.Views.КредитE); -lcs.LimitFunction = langdef.GetFunction(langdef.funcEQ, - new VariableDef(langdef.GuidType, Information.ExtractPropertyPath<Кредит>(x => x.Личность.Фамилия)), "Петров"); -var кредиты = DataServiceProvider.DataService.LoadObjects(lcs); +lcs.LimitFunction = languageDef.GetFunction(languageDef.funcEQ, + new VariableDef(languageDef.GuidType, Information.ExtractPropertyPath<Кредит>(x => x.Личность.Фамилия)), "Петров"); +var кредиты = ds.LoadObjects(lcs); ``` -{% include important.html content="Следует убедиться, что в представлении `КредитE` есть мастер `Личность` и его поле `Фамилия`, иначе произойдёт ошибка при выполнении запроса." %} +> Следует убедиться, что в представлении `КредитE` есть мастер `Личность` и его поле `Фамилия`, иначе произойдёт ошибка при выполнении запроса. ## Список функций diff --git a/pages/products/flexberry-orm/query-language/fo_limit-details.ru.md b/pages/products/flexberry-orm/query-language/fo_limit-details.ru.md index 130c95540..24c318440 100644 --- a/pages/products/flexberry-orm/query-language/fo_limit-details.ru.md +++ b/pages/products/flexberry-orm/query-language/fo_limit-details.ru.md @@ -8,15 +8,15 @@ permalink: ru/fo_limit-details.html lang: ru --- -Если необходимо задать условие на существование [детейлов](fd_key-concepts.html) по условию, в котором должно участвовать свойство [агрегатора](fd_key-concepts.html), необходимо использовать функцию [Exist](fo_exist-details.html). При указании свойств в условии для функции `Exist` необходимо явно указывать, что это свойство агрегатора: +Если необходимо задать условие на существование [детейлов](fd_key-concepts.html) по условию, в котором должно участвовать свойство [агрегатора](fd_key-concepts.html), необходимо использовать функцию [Exist](fo_exist-details.html). При указании свойств в условии для функции `Exist` необходимо явно указывать, что это свойство агрегатора: -``` +```h <Имя агрегирующего свойства у детейла>.<Свойство агрегатора>. ``` ## Пример наложения ограничения на детейлы с использованием свойства агрегатора -![](/images/pages/products/flexberry-orm/query-language/exist-example.png) +![exist-example](/images/pages/products/flexberry-orm/query-language/exist-example.png) Выявить ошибочно занесенные данные в базе: найти все компании, у которых существует программный продукт созданный раньше создания самой компании. @@ -26,11 +26,13 @@ lang: ru View view2 = Information.GetView("SoftwareL", typeof(Software)); view.AddDetailInView("Software", view2, true); var lcs = LoadingCustomizationStruct.GetSimpleStruct(typeof(Company), view); - ExternalLangDef langDef = ExternalLangDef.LanguageDef; - var detail = new DetailVariableDef(langDef.GetObjectType("Details"), "Software", view2, "Company"); - lcs.LimitFunction = langDef.GetFunction(langDef.funcExist, detail, - langDef.GetFunction(langDef.funcL, - new VariableDef(langDef.DateTimeType, Information.ExtractPropertyPath(x => x.DateCreation)), - new VariableDef(langDef.DateTimeType, Information.ExtractPropertyPath(x => x.Company.DateCreation)))); - var dos = DataServiceProvider.DataService.LoadObjects(lcs); + IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. + IDataService ds = mainUnityContainer.Resolve(); + ExternalLangDef languageDef = new ExternalLangDef(ds); + var detail = new DetailVariableDef(languageDef.GetObjectType("Details"), "Software", view2, "Company"); + lcs.LimitFunction = languageDef.GetFunction(languageDef.funcExist, detail, + languageDef.GetFunction(languageDef.funcL, + new VariableDef(languageDef.DateTimeType, Information.ExtractPropertyPath(x => x.DateCreation)), + new VariableDef(languageDef.DateTimeType, Information.ExtractPropertyPath(x => x.Company.DateCreation)))); + var dos = ds.LoadObjects(lcs); ``` diff --git a/pages/products/flexberry-orm/query-language/fo_limit-function-serialization.ru.md b/pages/products/flexberry-orm/query-language/fo_limit-function-serialization.ru.md index a21ba735f..06e1c0b7b 100644 --- a/pages/products/flexberry-orm/query-language/fo_limit-function-serialization.ru.md +++ b/pages/products/flexberry-orm/query-language/fo_limit-function-serialization.ru.md @@ -36,7 +36,9 @@ private void Serialize(bool binary) DateTime start = DateTime.Now; string fnStr = ""; - ExternalLangDef externalLangDef = ExternalLangDef.LanguageDef; + IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. + IDataService ds = mainUnityContainer.Resolve(); + ExternalLangDef languageDef = new ExternalLangDef(ds); SQLWhereLanguageDef ldef = SQLWhereLanguageDef.LanguageDef; Function fn = ldef.GetFunction( ldef.funcAND, @@ -56,22 +58,22 @@ private void Serialize(bool binary) string serializedFn; if (binary) { - serializedFn = ToolBinarySerializer.ObjectToString(externalLangDef.FunctionToSimpleStruct(fn)); + serializedFn = ToolBinarySerializer.ObjectToString(languageDef.FunctionToSimpleStruct(fn)); } else { - serializedFn = ToolXML.ObjectToString(externalLangDef.FunctionToSimpleStruct(fn)); + serializedFn = ToolXML.ObjectToString(languageDef.FunctionToSimpleStruct(fn)); } Assert.IsNotNull(serializedFn); Function восставшийИзНебытия; if (binary) { восставшийИзНебытия = - externalLangDef.FunctionFromSimpleStruct(ToolBinarySerializer.ObjectFromString(serializedFn)); + languageDef.FunctionFromSimpleStruct(ToolBinarySerializer.ObjectFromString(serializedFn)); } else { - восставшийИзНебытия = externalLangDef.FunctionFromSimpleStruct(ToolXML.ObjectFromString(serializedFn)); + восставшийИзНебытия = languageDef.FunctionFromSimpleStruct(ToolXML.ObjectFromString(serializedFn)); } Assert.IsNotNull(восставшийИзНебытия); fnStr = "Длина сериализованной строки: " + serializedFn.Length + Environment.NewLine diff --git a/pages/products/flexberry-orm/query-language/fo_linq-provider-faetures.ru.md b/pages/products/flexberry-orm/query-language/fo_linq-provider-faetures.ru.md index fcda414a5..0a4193bb9 100644 --- a/pages/products/flexberry-orm/query-language/fo_linq-provider-faetures.ru.md +++ b/pages/products/flexberry-orm/query-language/fo_linq-provider-faetures.ru.md @@ -1,235 +1,239 @@ ---- -title: Возможности LinqProvider -sidebar: flexberry-orm_sidebar -keywords: Flexberry ORM, Ограничения -summary: Поддерживаемые типы, особенности, ограничения и использование в объектах с агрегацией, примеры использования -toc: true -permalink: ru/fo_linq-provider-faetures.html -lang: ru ---- - -Ниже описаны основные возможности, предоставляемые [LINQProvider](fo_linq-provider.html). - -В примерах `ds` - это сервис данных, полученный следующим образом: - -``` csharp -var ds = (SQLDataService)DataServiceProvider.DataService; -``` - -## Поддерживаемые типы - -### Числа - -Помимо численных атрибутов объекта в запросах допускается использовать константы, переменные, а так же функции от них. Все это будет вычислено. -Например, запрос выдающий все объекты с атрибутом Длина, равным атрибуту Ширина + 10: - -``` csharp -int Number1 = 8; -int Number2 = 2; -IQueryable<Кошка> queryList = ds.Query<Кошка>(); -IQueryable<Кошка> query = from pn in queryList where pn.Длина == Number1 + Number2 + pn.Ширина select pn; -List data = query.Cast().ToList(); -``` - -Поддерживаются не только целые числа при построении ограничений. - -``` csharp -float length = 10.0f; -IQueryable<Улица> queryList = ds.Query<Улица>(); -IQueryable<Улица> query = from pn in queryList where pn.Протяженность > length select pn; -List data = query.Cast().ToList(); -``` - -### Строки - -#### Contains, StartsWith, EndsWith - -Для работы со строками [Linq-провайдер](fo_linq-provider.html) позволяет использовать методы Contains, а также варианты StartsWith, EndsWith с одним оператором. Использование других вариантов StartsWith и EndsWith вызовет исключение `MethodSignatureException`. - -**Выбрать кошек, чьи клички содержат подстроку “ош”** - -``` csharp -List<Кошка> cat = ds.Query<Кошка>(Кошка.Views.КошкаE).Where(o => o.Кличка.Contains("ош")).ToList(); -``` - -#### Regex - -В [LINQProvider](fo_linq-provider.html) есть минимальная поддержка Regex (основные ограничения связаны с тем, что шаблон для регулярного выражения переводится в шаблон поиска для конструкции like в sql). - -``` csharp -List<Порода> objss = ds.Query<Порода>(Порода.Views.ПородаE).Where(x => Regex.IsMatch(x.Название, "12.*3")).ToList(); -``` - -Допустимые для использования в регулярных выражениях конструкции: ".", ".*", "^", "$". - -### Дата/Время - -Для наложения ограничений на даты можно использовать различные свойства `DateTime`. - -[Linq-провайдер](fo_linq-provider.html) не поддерживает метод `DateTime.AddDays`. При попытке ее использования будет брошено исключение `NotImplementedException`. - -Можно использовать числовые компоненты даты, такие как год, месяц, день в месяце, час минута, день недели. При этом дни недели преобразуются в числа как в C# в перечислении `DayOfWeek` (0 – воскресение, 1 – понедельник .. 6 – суббота). Для этого в [была добавлена функция DayOfWeekZeroBased в дополнение к старой DayOfWeek](fo_external-lang-def.html). - -При попытке использования свойств Ticks, Second, Millisecond, DayOfYear будет брошено исключение `MethodSignatureException`. - -**Выбрать переломы которые были раньше, чем сегодня:** - -``` csharp -List<Перелом> objss = ds.Query<Перелом>(Перелом.Views.ПереломE).Where(o => o.Дата.Date < DateTime.Now.Date).ToList(); -``` - -**Применение AddYears** - -``` csharp -DateTime now = DateTime.Now; -List<Перелом> objss = ds.Query<Перелом>(Перелом.Views.ПереломE).Where(o => o.Дата.AddYears(1) < now.Date).ToList(); -``` - -**Выбрать переломы, произошедшие в воскресение.** - -``` csharp -List<Перелом> objss = ds.Query<Перелом>(Перелом.Views.ПереломE).Where(o => o.Дата.DayOfWeek == DayOfWeek.Sunday).ToList(); -``` - -#### NullableDateTime - -Чтобы произвести сравнение `NullableDateTime` с `DateTime` нужно привести их к одному типу __вне__ Linq-запроса. - -``` csharp -DateTime date = new DateTime(2012, 1, 1); -NullableDateTime nullableDate = new NullableDateTime { Value = date }; -// ДатаВыдачи имеет тип NullableDateTime. -List<Кредит> objss = ds.Query<Кредит>(Кредит.Views.КредитE).Where(к => к.ДатаВыдачи < nullableDate).ToList(); -``` - -### Логический тип - -Возможно использование не только выражений, но и их комбинаций с помощью операций алгебры логики, а так же использование констант true и false. - -### Перечисление (enum) - -Ограничение на перечисление ркомендовано накладывать следующим образом: - -``` csharp -// Сначала кэшируем значение enum в переменной, только потом ограничиваем -var типПерелома = ТипПерелома.Открытый; -ds.Query<Перелом>(Перелом.Views.ПереломE).Where(o => o.Тип == типПерелома).ToList(); -``` - -## Общие возможности и особенности - -### Сравнение с null - -При сравнении с null доступна не только проверка на равенство и неравенство, но и работа с операциями ">", ">=", "<", "<=". - -Как и при стандартной работе с Linq, выражение вида "`Property > null`", где `Property`, например, типа `int`, вернёт `false`. - -``` csharp -ds.Query<Лапа>(Лапа.Views.ЛапаE).Where(x => x.РазмерNullableInt > null); -``` - -### Выполнение простейших арифметических операций - -Внутри Linq-выражения доступно выполнение простейших арифметических операций: - -``` csharp -string prefix = "prefix"; -string postfix = "postfix"; -ds.Query<Кошка>(Кошка.Views.КошкаE).Where(x => x.Кличка == prefix + postfix); -``` - -## Ограничения LINQProvider - -Среди крупных ограничений можно указать "проекции" (проецирование из текущего типа выборки, т.е. потомков DataObject, какого-то другого типа), а также задания ограничений с использованием группировки (Group By). - -Для использования проекции или группировки необходимо: - -* Получить коллекцию объектов данных, для которой требуется группировка или проекция, с помощью [LINQProvider](fo_linq-provider.html). -* Сделать дополнительный запрос к полученной коллекции с использованием [LINQ to Objects](https://msdn.microsoft.com/ru-ru/library/bb397919.aspx). - -## Работа с мастерами/детейлами/псевдодетейлами - -### Ключи (PrimaryKey): - -Для сравнения объектов по [ключу](fo_primary-keys-objects.html) необходимо использовать метод `Equals`: - -``` csharp -ds.Query<Кошка>(Кошка.Views.КошкаE).Where(o => o.__PrimaryKey.Equals(кошка.__PrimaryKey)); -``` - -### Мастера - -Имеется возможность наложить ограничение на мастера, либо его атрибуты типа int, long, bool, string, DateTime. -Например: - -``` csharp -Порода порода = ds.Query<Порода>(Порода.Views.ПородаE).First(); // Какой-нибудь объект типа порода -Кошка кошка = ds.Query<Кошка>(Кошка.Views.КошкаE).FirstOrDefault(o => o.Порода == порода); //Получить первую кошку данной породы -Кошка кошка2 = ds.Query<Кошка>(Кошка.Views.КошкаE).FirstOrDefault(o => o.Порода.Название == "Дикая"); // Получить кошку по названию породы -``` - -При этом допускаются ограничения только на мастеров первого уровня. При попытке выполнить следующий код будет брошено исключение `MasterLevelException`. - -``` csharp -Кошка кошка = ds.Query<Кошка>(Кошка.Views.КошкаE).FirstOrDefault(o => o.Порода.ТипПороды == порода.ТипПороды); //Использование мастера мастера вызовет исключение -``` - -Но можно наложить ограничение на мастера n-го уровня по его PrimaryKey: - -``` csharp -ds.Query<Кошка>(Кошка.Views.КошкаE).Where(o => ПородаPKs.Contains(o.Порода.ТипПороды.__PrimaryKey)); -``` - -### Детейлы - -С учётом [особенностей написания Linq-запросов к массивам детейлов](fo_functionality-work-detail-array.html): - -``` csharp -ds.Query<Порода>(Порода.Views.КотенокE).Where( - x => x.Кошка.Лапа.Cast<Лапа>().Any(o => o.ТипЛапы.Название == "передняя")).ToList(); -``` - -### Псевдодетейлы - -Работа с псевдодетейлами описана в статье [Псевдодетейлы в LinqProvider](fo_psedodetails-linq-provider.html). - -## Примеры использования - -* Простая вычитка всех записей: - -``` csharp -var credits = ds.Query<Кредит>(Кредит.Views.КредитL.Name); -``` -* Наложение ограничений на строковое поле: - -``` csharp -var личности = ds.Query<Личность>(Личность.Views.ЧеловекL.Name).Where(l => l.Фамилия == "Петров"); -``` -* Наложение ограничений на дату: - -``` csharp -var личности = ds.Query<Личность>(Личность.Views.ЧеловекL.Name).Where(l => l.ДатаРождения > new DateTime(1980, 1, 1)); -``` - -* Наложение ограничений на логический тип: - -``` csharp -var личности = ds.Query<Личность>(Личность.Views.ЧеловекL.Name).Where(l => l.Уволен); -``` - -* Разумеется, условия можно комбинировать: - -``` csharp -var личности = ds.Query<Личность>(Личность.Views.ЧеловекL.Name).Where(l => l.Уволен && l.ДатаУвольнения > new DateTime(2012, 1, 1)); -``` - -* Наложение ограничений на мастер (по ключу): - -``` csharp -var кредиты = ds.Query<Кредит>(Кредит.Views.КредитL.Name).Where(k => k.Клиент == klient); -``` -* Наложение ограничений на детейлы: - -``` csharp -ds.Query<Порода>(Порода.Views.КотенокE).Where(x => x.Кошка.Лапа.Cast<Лапа>().Any(o => o.ТипЛапы.Название == "передняя")).ToList(); -``` +--- +title: Возможности LinqProvider +sidebar: flexberry-orm_sidebar +keywords: Flexberry ORM, Ограничения +summary: Поддерживаемые типы, особенности, ограничения и использование в объектах с агрегацией, примеры использования +toc: true +permalink: ru/fo_linq-provider-faetures.html +lang: ru +--- + +Ниже описаны основные возможности, предоставляемые [LINQProvider](fo_linq-provider.html). + +В примерах `ds` - это сервис данных, полученный следующим образом: + +``` csharp +IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. +IDataService ds = mainUnityContainer.Resolve(); +``` + +## Поддерживаемые типы + +### Числа + +Помимо численных атрибутов объекта в запросах допускается использовать константы, переменные, а так же функции от них. Все это будет вычислено. +Например, запрос выдающий все объекты с атрибутом Длина, равным атрибуту Ширина + 10: + +``` csharp +int Number1 = 8; +int Number2 = 2; +IQueryable<Кошка> queryList = ds.Query<Кошка>(); +IQueryable<Кошка> query = from pn in queryList where pn.Длина == Number1 + Number2 + pn.Ширина select pn; +List data = query.Cast().ToList(); +``` + +Поддерживаются не только целые числа при построении ограничений. + +``` csharp +float length = 10.0f; +IQueryable<Улица> queryList = ds.Query<Улица>(); +IQueryable<Улица> query = from pn in queryList where pn.Протяженность > length select pn; +List data = query.Cast().ToList(); +``` + +### Строки + +#### Contains, StartsWith, EndsWith + +Для работы со строками [Linq-провайдер](fo_linq-provider.html) позволяет использовать методы Contains, а также варианты StartsWith, EndsWith с одним оператором. Использование других вариантов StartsWith и EndsWith вызовет исключение `MethodSignatureException`. + +_Выбрать кошек, чьи клички содержат подстроку “ош”._ + +``` csharp +List<Кошка> cat = ds.Query<Кошка>(Кошка.Views.КошкаE).Where(o => o.Кличка.Contains("ош")).ToList(); +``` + +#### Regex + +В [LINQProvider](fo_linq-provider.html) есть минимальная поддержка Regex (основные ограничения связаны с тем, что шаблон для регулярного выражения переводится в шаблон поиска для конструкции like в sql). + +``` csharp +List<Порода> objss = ds.Query<Порода>(Порода.Views.ПородаE).Where(x => Regex.IsMatch(x.Название, "12.*3")).ToList(); +``` + +Допустимые для использования в регулярных выражениях конструкции: ".", ".*", "^", "$". + +### Дата/Время + +Для наложения ограничений на даты можно использовать различные свойства `DateTime`. + +[Linq-провайдер](fo_linq-provider.html) не поддерживает метод `DateTime.AddDays`. При попытке ее использования будет брошено исключение `NotImplementedException`. + +Можно использовать числовые компоненты даты, такие как год, месяц, день в месяце, час минута, день недели. При этом дни недели преобразуются в числа как в C# в перечислении `DayOfWeek` (0 – воскресение, 1 – понедельник .. 6 – суббота). Для этого в [была добавлена функция DayOfWeekZeroBased в дополнение к старой DayOfWeek](fo_external-lang-def.html). + +При попытке использования свойств Ticks, Second, Millisecond, DayOfYear будет брошено исключение `MethodSignatureException`. + +**Выбрать переломы которые были раньше, чем сегодня:** + +``` csharp +List<Перелом> objss = ds.Query<Перелом>(Перелом.Views.ПереломE).Where(o => o.Дата.Date < DateTime.Now.Date).ToList(); +``` + +**Применение AddYears:** + +``` csharp +DateTime now = DateTime.Now; +List<Перелом> objss = ds.Query<Перелом>(Перелом.Views.ПереломE).Where(o => o.Дата.AddYears(1) < now.Date).ToList(); +``` + +**Выбрать переломы, произошедшие в воскресение.** + +``` csharp +List<Перелом> objss = ds.Query<Перелом>(Перелом.Views.ПереломE).Where(o => o.Дата.DayOfWeek == DayOfWeek.Sunday).ToList(); +``` + +#### NullableDateTime + +Чтобы произвести сравнение `NullableDateTime` с `DateTime` нужно привести их к одному типу _вне_ Linq-запроса. + +``` csharp +DateTime date = new DateTime(2012, 1, 1); +NullableDateTime nullableDate = new NullableDateTime { Value = date }; +// ДатаВыдачи имеет тип NullableDateTime. +List<Кредит> objss = ds.Query<Кредит>(Кредит.Views.КредитE).Where(к => к.ДатаВыдачи < nullableDate).ToList(); +``` + +### Логический тип + +Возможно использование не только выражений, но и их комбинаций с помощью операций алгебры логики, а так же использование констант true и false. + +### Перечисление (enum) + +Ограничение на перечисление ркомендовано накладывать следующим образом: + +``` csharp +// Сначала кэшируем значение enum в переменной, только потом ограничиваем +var типПерелома = ТипПерелома.Открытый; +ds.Query<Перелом>(Перелом.Views.ПереломE).Where(o => o.Тип == типПерелома).ToList(); +``` + +## Общие возможности и особенности + +### Сравнение с null + +При сравнении с null доступна не только проверка на равенство и неравенство, но и работа с операциями ">", ">=", "<", "<=". + +Как и при стандартной работе с Linq, выражение вида "`Property > null`", где `Property`, например, типа `int`, вернёт `false`. + +``` csharp +ds.Query<Лапа>(Лапа.Views.ЛапаE).Where(x => x.РазмерNullableInt > null); +``` + +### Выполнение простейших арифметических операций + +Внутри Linq-выражения доступно выполнение простейших арифметических операций: + +``` csharp +string prefix = "prefix"; +string postfix = "postfix"; +ds.Query<Кошка>(Кошка.Views.КошкаE).Where(x => x.Кличка == prefix + postfix); +``` + +## Ограничения LINQProvider + +Среди крупных ограничений можно указать "проекции" (проецирование из текущего типа выборки, т.е. потомков DataObject, какого-то другого типа), а также задания ограничений с использованием группировки (Group By). + +Для использования проекции или группировки необходимо: + +* Получить коллекцию объектов данных, для которой требуется группировка или проекция, с помощью [LINQProvider](fo_linq-provider.html). +* Сделать дополнительный запрос к полученной коллекции с использованием [LINQ to Objects](https://msdn.microsoft.com/ru-ru/library/bb397919.aspx). + +## Работа с мастерами/детейлами/псевдодетейлами + +### Ключи (PrimaryKey) + +Для сравнения объектов по [ключу](fo_primary-keys-objects.html) необходимо использовать метод `Equals`: + +``` csharp +ds.Query<Кошка>(Кошка.Views.КошкаE).Where(o => o.__PrimaryKey.Equals(кошка.__PrimaryKey)); +``` + +### Мастера + +Имеется возможность наложить ограничение на мастера, либо его атрибуты типа int, long, bool, string, DateTime. +Например: + +``` csharp +Порода порода = ds.Query<Порода>(Порода.Views.ПородаE).First(); // Какой-нибудь объект типа порода +Кошка кошка = ds.Query<Кошка>(Кошка.Views.КошкаE).FirstOrDefault(o => o.Порода == порода); //Получить первую кошку данной породы +Кошка кошка2 = ds.Query<Кошка>(Кошка.Views.КошкаE).FirstOrDefault(o => o.Порода.Название == "Дикая"); // Получить кошку по названию породы +``` + +При этом допускаются ограничения только на мастеров первого уровня. При попытке выполнить следующий код будет брошено исключение `MasterLevelException`. + +``` csharp +Кошка кошка = ds.Query<Кошка>(Кошка.Views.КошкаE).FirstOrDefault(o => o.Порода.ТипПороды == порода.ТипПороды); //Использование мастера мастера вызовет исключение +``` + +Но можно наложить ограничение на мастера n-го уровня по его PrimaryKey: + +``` csharp +ds.Query<Кошка>(Кошка.Views.КошкаE).Where(o => ПородаPKs.Contains(o.Порода.ТипПороды.__PrimaryKey)); +``` + +### Детейлы + +С учётом [особенностей написания Linq-запросов к массивам детейлов](fo_functionality-work-detail-array.html): + +``` csharp +ds.Query<Порода>(Порода.Views.КотенокE).Where( + x => x.Кошка.Лапа.Cast<Лапа>().Any(o => o.ТипЛапы.Название == "передняя")).ToList(); +``` + +### Псевдодетейлы + +Работа с псевдодетейлами описана в статье [Псевдодетейлы в LinqProvider](fo_psedodetails-linq-provider.html). + +## Примеры использования + +* Простая вычитка всех записей: + +``` csharp +var credits = ds.Query<Кредит>(Кредит.Views.КредитL.Name); +``` + +* Наложение ограничений на строковое поле: + +``` csharp +var личности = ds.Query<Личность>(Личность.Views.ЧеловекL.Name).Where(l => l.Фамилия == "Петров"); +``` + +* Наложение ограничений на дату: + +``` csharp +var личности = ds.Query<Личность>(Личность.Views.ЧеловекL.Name).Where(l => l.ДатаРождения > new DateTime(1980, 1, 1)); +``` + +* Наложение ограничений на логический тип: + +``` csharp +var личности = ds.Query<Личность>(Личность.Views.ЧеловекL.Name).Where(l => l.Уволен); +``` + +* Разумеется, условия можно комбинировать: + +``` csharp +var личности = ds.Query<Личность>(Личность.Views.ЧеловекL.Name).Where(l => l.Уволен && l.ДатаУвольнения > new DateTime(2012, 1, 1)); +``` + +* Наложение ограничений на мастер (по ключу): + +``` csharp +var кредиты = ds.Query<Кредит>(Кредит.Views.КредитL.Name).Where(k => k.Клиент == klient); +``` + +* Наложение ограничений на детейлы: + +``` csharp +ds.Query<Порода>(Порода.Views.КотенокE).Where(x => x.Кошка.Лапа.Cast<Лапа>().Any(o => o.ТипЛапы.Название == "передняя")).ToList(); +``` diff --git a/pages/products/flexberry-orm/query-language/fo_linq-provider.ru.md b/pages/products/flexberry-orm/query-language/fo_linq-provider.ru.md index 942a99696..4f061968e 100644 --- a/pages/products/flexberry-orm/query-language/fo_linq-provider.ru.md +++ b/pages/products/flexberry-orm/query-language/fo_linq-provider.ru.md @@ -1,103 +1,111 @@ ---- -title: LINQProvider -sidebar: flexberry-orm_sidebar -keywords: Flexberry ORM, Ограничения -summary: -toc: true -permalink: ru/fo_linq-provider.html -lang: ru ---- - -## Поддержка Linq - -Класс `LinqToLcs` пространства имен `ICSSoft.STORMNET.Business.LINQProvider` предназначен для поддержки [LINQ](http://ru.wikipedia.org/wiki/LINQ) запросов к сервисам данных [`SQLDataService`](fo_sql-data-service.html). - -Основные возможности LINQProvider описаны в статье [Возможности LinqProvider](fo_linq-provider-faetures.html). - -## Как использовать LinqProvider - -Для работы LINQ-провайдера необходима ссылка на System.Linq - -``` csharp - using System.Linq; -``` - -**А также проектная ссылка на `ICSSoft.STORMNET.Business.MSSQLDataService.DLL`.** - -При подключении пространства имен `ICSSoft.STORMNET.Business.LINQProvider` объектам [SQLDataService](fo_sql-data-service.html) добавляется метод Query со следующими прототипами: - -``` csharp -public static IQueryable Query(this SQLDataService ds, string viewName) where T : DataObject - -public static IQueryable Query(this SQLDataService ds, View view, IEnumerable resolvingViews = null) where T : DataObject - -public static IQueryable Query(this SQLDataService ds) where T : DataObject -``` - -Параметры: - -| Имя | Описание | -|:----|:----| -| `ds` | [Сервис данных, наследник SQLDataService](fo_sql-data-service.html), для выполнения запроса| -| `view` | [Представление](fd_view-definition.html), используемое для загрузки объектов| -| `resolvingViews` | [Представление](fd_view-definition.html) мастеров, содержащие их детейлы, используемые в запросе (если таких нет, то `null`)| - -В последнем варианте перегрузки [представление](fd_view-definition.html) для загрузки объектов будет формироваться динамически (в него попадут свойства, использующиеся в запросе). - -При этом, если представление задается статически, предпочтительнее использовать второй вариант перегрузки, указав представление в виде `Тип.Views.ИмяТипа`. - -Метод возвращает `IQueryable`, которому можно передать запрос с помощью методов-расширений LINQ: -* [Where](http://msdn.microsoft.com/en-us/library/system.linq.queryable.where.aspx) -* [First](http://msdn.microsoft.com/en-us/library/system.linq.queryable.first.aspx) -* [Any](http://msdn.microsoft.com/en-us/library/system.linq.queryable.any.aspx) -* [All](http://msdn.microsoft.com/en-us/library/bb534754.aspx) -* [Count](http://msdn.microsoft.com/en-us/library/bb534754.aspx) -* [FirstOrDefault](http://msdn.microsoft.com/ru-ru/library/system.linq.queryable.firstordefault.aspx) - -{% include note.html content="Вычитка происходит каждый раз при вызове ToList или ToArray, так что желательно сначала получить коллекцию данных, а потом работать с ней." %} - -## Примеры использования - -### Получение первого подходящего объекта - -``` csharp -using ICSSoft.STORMNET.Business; -using ICSSoft.STORMNET.Business.LINQProvider; -//... -var ds = (SQLDataService)DataServiceProvider.DataService; // Cервис данных. -Кошка cat = ds.Query<Кошка>(Кошка.Views.КошкаE).First(o => o.Кличка.Contains("ош")); // Получение объекта. -Console.WriteLine(cat.Кличка); //Использование. -``` - -### Получение первого подходящего объекта (с генерацией `TOP 1` в тексте запроса при применении `FirstOrDefault` и `First`) - -``` csharp -using ICSSoft.STORMNET.Business; -using ICSSoft.STORMNET.Business.LINQProvider; -//... -var ds = (SQLDataService)DataServiceProvider.DataService; // Cервис данных. -Кошка cat = ds.Query<Кошка>(Кошка.Views.КошкаE).Where(o => o.Кличка.Contains("ош")).Take(1).FirstOrDefault(); // Получение объекта. -Console.WriteLine(cat.Кличка); //Использование. -``` - -### Получение коллекции объектов - -``` csharp -using ICSSoft.STORMNET.Business; -using ICSSoft.STORMNET.Business.LINQProvider; -//... -var ds = (SQLDataService)DataServiceProvider.DataService; // Сервис данных. -IQueryable<Кошка> objs = ds.Query<Кошка>(Кошка.Views.КошкаE); -IQueryable<Кошка> query = from o in objs where o.PrimaryKey == "6211E0DE-3E7A-4A68-866A-AB206A005B1C" select o; // Получить кошек по заданному значению ключа. -List<Кошка> data = query.ToList(); // Вычитать данные в коллекцию. -Console.WriteLine(data[0).Кличка); // Пользуемся полученными данными. -``` - -#### Следующий код эквивалентен предыдущему - -``` csharp -var ds = (SQLDataService)DataServiceProvider.DataService; // Сервис данных. -IQueryable<Кошка> objs = ds.Query<Кошка>(Кошка.Views.КошкаE).Where(o => o.PrimaryKey == "6211E0DE-3E7A-4A68-866A-AB206A005B1C"); // Получить кошек по заданному значению ключа. -List<Кошка> data = objs.ToList(); // Вычитать данные в коллекцию. -Console.WriteLine(data[0).Кличка); // Пользуемся полученными данными. -``` +--- +title: LINQProvider +sidebar: flexberry-orm_sidebar +keywords: Flexberry ORM, Ограничения +summary: +toc: true +permalink: ru/fo_linq-provider.html +lang: ru +--- + +## Поддержка Linq + +Класс `LinqToLcs` пространства имен `ICSSoft.STORMNET.Business.LINQProvider` предназначен для поддержки [LINQ](http://ru.wikipedia.org/wiki/LINQ) запросов к сервисам данных [`SQLDataService`](fo_sql-data-service.html). + +Основные возможности LINQProvider описаны в статье [Возможности LinqProvider](fo_linq-provider-faetures.html). + +## Как использовать LinqProvider + +Для работы LINQ-провайдера необходима ссылка на System.Linq + +``` csharp + using System.Linq; +``` + +**А также проектная ссылка на `ICSSoft.STORMNET.Business.MSSQLDataService.DLL`.** + +При подключении пространства имен `ICSSoft.STORMNET.Business.LINQProvider` объектам [SQLDataService](fo_sql-data-service.html) добавляется метод Query со следующими прототипами: + +``` csharp +public static IQueryable Query(this SQLDataService ds, string viewName) where T : DataObject + +public static IQueryable Query(this SQLDataService ds, View view, IEnumerable resolvingViews = null) where T : DataObject + +public static IQueryable Query(this SQLDataService ds) where T : DataObject +``` + +Параметры: + +| Имя | Описание | +|:----|:----| +| `ds` | [Сервис данных, наследник SQLDataService](fo_sql-data-service.html), для выполнения запроса| +| `view` | [Представление](fd_view-definition.html), используемое для загрузки объектов| +| `resolvingViews` | [Представление](fd_view-definition.html) мастеров, содержащие их детейлы, используемые в запросе (если таких нет, то `null`)| + +В последнем варианте перегрузки [представление](fd_view-definition.html) для загрузки объектов будет формироваться динамически (в него попадут свойства, использующиеся в запросе). + +При этом, если представление задается статически, предпочтительнее использовать второй вариант перегрузки, указав представление в виде `Тип.Views.ИмяТипа`. + +Метод возвращает `IQueryable`, которому можно передать запрос с помощью методов-расширений LINQ: +* [Where](http://msdn.microsoft.com/en-us/library/system.linq.queryable.where.aspx) +* [First](http://msdn.microsoft.com/en-us/library/system.linq.queryable.first.aspx) +* [Any](http://msdn.microsoft.com/en-us/library/system.linq.queryable.any.aspx) +* [All](http://msdn.microsoft.com/en-us/library/bb534754.aspx) +* [Count](http://msdn.microsoft.com/en-us/library/bb534754.aspx) +* [FirstOrDefault](http://msdn.microsoft.com/ru-ru/library/system.linq.queryable.firstordefault.aspx) + +{% include note.html content="Вычитка происходит каждый раз при вызове ToList или ToArray, так что желательно сначала получить коллекцию данных, а потом работать с ней." %} + +## Примеры использования + +### Получение первого подходящего объекта + +``` csharp +using ICSSoft.STORMNET.Business; +using ICSSoft.STORMNET.Business.LINQProvider; +//... +IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. +IDataService ds = mainUnityContainer.Resolve(); +SQLDataService sqldataservice = (SQLDataService)ds; // Cервис данных. +Кошка cat = sqldataservice.Query<Кошка>(Кошка.Views.КошкаE).First(o => o.Кличка.Contains("ош")); // Получение объекта. +Console.WriteLine(cat.Кличка); //Использование. +``` + +### Получение первого подходящего объекта (с генерацией `TOP 1` в тексте запроса при применении `FirstOrDefault` и `First`) + +``` csharp +using ICSSoft.STORMNET.Business; +using ICSSoft.STORMNET.Business.LINQProvider; +//... +IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. +IDataService ds = mainUnityContainer.Resolve(); +SQLDataService sqldataservice = (SQLDataService)ds; // Cервис данных. +Кошка cat = sqldataservice.Query<Кошка>(Кошка.Views.КошкаE).Where(o => o.Кличка.Contains("ош")).Take(1).FirstOrDefault(); // Получение объекта. +Console.WriteLine(cat.Кличка); //Использование. +``` + +### Получение коллекции объектов + +``` csharp +using ICSSoft.STORMNET.Business; +using ICSSoft.STORMNET.Business.LINQProvider; +//... +IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. +IDataService ds = mainUnityContainer.Resolve(); +SQLDataService sqldataservice = (SQLDataService)ds; // Cервис данных. // Сервис данных. +IQueryable<Кошка> objs = sqldataservice.Query<Кошка>(Кошка.Views.КошкаE); +IQueryable<Кошка> query = from o in objs where o.PrimaryKey == "6211E0DE-3E7A-4A68-866A-AB206A005B1C" select o; // Получить кошек по заданному значению ключа. +List<Кошка> data = query.ToList(); // Вычитать данные в коллекцию. +Console.WriteLine(data[0).Кличка); // Пользуемся полученными данными. +``` + +#### Следующий код эквивалентен предыдущему + +``` csharp +IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. +IDataService ds = mainUnityContainer.Resolve(); +SQLDataService sqldataservice = (SQLDataService)ds; // Cервис данных. +IQueryable<Кошка> objs = sqldataservice.Query<Кошка>(Кошка.Views.КошкаE).Where(o => o.PrimaryKey == "6211E0DE-3E7A-4A68-866A-AB206A005B1C"); // Получить кошек по заданному значению ключа. +List<Кошка> data = objs.ToList(); // Вычитать данные в коллекцию. +Console.WriteLine(data[0).Кличка); // Пользуемся полученными данными. +``` diff --git a/pages/products/flexberry-orm/query-language/fo_load-limitation-example.ru.md b/pages/products/flexberry-orm/query-language/fo_load-limitation-example.ru.md index 3bb7eb61a..77d8eafca 100644 --- a/pages/products/flexberry-orm/query-language/fo_load-limitation-example.ru.md +++ b/pages/products/flexberry-orm/query-language/fo_load-limitation-example.ru.md @@ -1,57 +1,59 @@ ---- -title: Пример наложения ограничений на загрузку объектов -sidebar: flexberry-orm_sidebar -keywords: Flexberry ORM, Ограничения, пример -summary: Наложение ограничения, сортировка, диапазон индексов загружаемых объектов -toc: true -permalink: ru/fo_load-limitation-example.html -lang: ru ---- - -Полный список примеров кода [Flexberry ORM](fo_flexberry-orm.html) находится в статье ["Примеры кода"](fo_code-samples.html). - -## Пример наложения ограничения на загружаемые объекты данных (условия, количество и т.д.) - -Обычно приложения не ограничиваются простой загрузкой объектов из БД: требуется сортировка, наложение условий на загружаемые объекты, на их индексы. -Для хранения и передачи сервису данных всей этой информации используется структура данных [`ICSSoft.STORMNET.Business.LoadingCustomizationStruct`](fo_loading-customization-struct.html). -В примере показано ее использование при загрузке объектов данных: наложение ограничения, сортировка, диапазон индексов загружаемых объектов. - -```csharp -Console.WriteLine("3. How to load a set of dataobjects in specific view, limitation, quantity, etc.."); - -// Во Flexberry ORM есть разные наборы операций (языки) для задание ограничений. Самый простой - SQLWhereLanguageDef. -ICSSoft.STORMNET.FunctionalLanguage.SQLWhere.SQLWhereLanguageDef ld = - ICSSoft.STORMNET.FunctionalLanguage.SQLWhere.SQLWhereLanguageDef.LanguageDef; - -// Создаем структуру, хранящую параметры загрузки объектов (представление, типы данных, ограничение и т.д.). -LoadingCustomizationStruct lcs = new LoadingCustomizationStruct(null); -lcs.View = CD.Views.CD_E; -lcs.LoadingTypes = new[] { typeof(CDDA), typeof(CDDD), typeof(DVD) }; - -// Ограничение, использующие свойства классов, на которые ссылается класс CS. Могут быть использованы те свойства, -// которые указаны в представлении, по которому производится загрузка объектов. -lcs.LimitFunction = ld.GetFunction(ld.funcEQ, - new VariableDef(ld.StringType, Information.ExtractPropertyPath(c => c.Publisher.Country.Name)), "USA"); - -// Параметры сортировки загружаемых объектов. Указать можно также только свойства, которые есть в представлении. -lcs.ColumnsSort = new[] { new ColumnsSortDef(Information.ExtractPropertyName(c => c.Name), ICSSoft.STORMNET.Business.SortOrder.Asc) }; - -Stopwatch stopwatch = new Stopwatch(); -stopwatch.Start(); - -// Можно указать диапазон индексов загружаемых объектов, что удобно, например, для постраничного вывода. -// lcs.RowNumber = new RowNumberDef(2, 5); -// Есть три основных метода для загрузки объектов: -// 1. Загрузить из БД записи и для каждой из них создать экземпляр объекта данных. -ICSSoft.STORMNET.DataObject[] objs = DataServiceProvider.DataService.LoadObjects(lcs); - -// 2. Загрузить без создания экземпляров (каждый объект представлен в виде строки из значений свойств с разделителями). -// Используется, когда не требуется редактирование объектов. Он намного быстрее! -ObjectStringDataView[] stringedview = DataServiceProvider.DataService.LoadStringedObjectView(';', lcs); - -// 3. Получить количество объектов, без загрузки данных. -int iObjsCount = DataServiceProvider.DataService.GetObjectsCount(lcs); - -stopwatch.Stop(); -Console.WriteLine("Time taken for all loadings: {0} ms.", stopwatch.ElapsedMilliseconds); -``` +--- +title: Пример наложения ограничений на загрузку объектов +sidebar: flexberry-orm_sidebar +keywords: Flexberry ORM, Ограничения, пример +summary: Наложение ограничения, сортировка, диапазон индексов загружаемых объектов +toc: true +permalink: ru/fo_load-limitation-example.html +lang: ru +--- + +Полный список примеров кода [Flexberry ORM](fo_flexberry-orm.html) находится в статье ["Примеры кода"](fo_code-samples.html). + +## Пример наложения ограничения на загружаемые объекты данных (условия, количество и т.д.) + +Обычно приложения не ограничиваются простой загрузкой объектов из БД: требуется сортировка, наложение условий на загружаемые объекты, на их индексы. +Для хранения и передачи сервису данных всей этой информации используется структура данных [`ICSSoft.STORMNET.Business.LoadingCustomizationStruct`](fo_loading-customization-struct.html). +В примере показано ее использование при загрузке объектов данных: наложение ограничения, сортировка, диапазон индексов загружаемых объектов. + +```csharp +Console.WriteLine("3. How to load a set of dataobjects in specific view, limitation, quantity, etc.."); + +// Во Flexberry ORM есть разные наборы операций (языки) для задание ограничений. Самый простой - SQLWhereLanguageDef. +ICSSoft.STORMNET.FunctionalLanguage.SQLWhere.SQLWhereLanguageDef ld = + ICSSoft.STORMNET.FunctionalLanguage.SQLWhere.SQLWhereLanguageDef.LanguageDef; + +// Создаем структуру, хранящую параметры загрузки объектов (представление, типы данных, ограничение и т.д.). +LoadingCustomizationStruct lcs = new LoadingCustomizationStruct(null); +lcs.View = CD.Views.CD_E; +lcs.LoadingTypes = new[] { typeof(CDDA), typeof(CDDD), typeof(DVD) }; + +// Ограничение, использующие свойства классов, на которые ссылается класс CS. Могут быть использованы те свойства, +// которые указаны в представлении, по которому производится загрузка объектов. +lcs.LimitFunction = ld.GetFunction(ld.funcEQ, + new VariableDef(ld.StringType, Information.ExtractPropertyPath(c => c.Publisher.Country.Name)), "USA"); + +// Параметры сортировки загружаемых объектов. Указать можно также только свойства, которые есть в представлении. +lcs.ColumnsSort = new[] { new ColumnsSortDef(Information.ExtractPropertyName(c => c.Name), ICSSoft.STORMNET.Business.SortOrder.Asc) }; + +Stopwatch stopwatch = new Stopwatch(); +stopwatch.Start(); + +// Можно указать диапазон индексов загружаемых объектов, что удобно, например, для постраничного вывода. +// lcs.RowNumber = new RowNumberDef(2, 5); +// Есть три основных метода для загрузки объектов: +// 1. Загрузить из БД записи и для каждой из них создать экземпляр объекта данных. +IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. +IDataService ds = mainUnityContainer.Resolve(); +ICSSoft.STORMNET.DataObject[] objs = ds.LoadObjects(lcs); + +// 2. Загрузить без создания экземпляров (каждый объект представлен в виде строки из значений свойств с разделителями). +// Используется, когда не требуется редактирование объектов. Он намного быстрее! +ObjectStringDataView[] stringedview =ds.LoadStringedObjectView(';', lcs); + +// 3. Получить количество объектов, без загрузки данных. +int iObjsCount = ds.GetObjectsCount(lcs); + +stopwatch.Stop(); +Console.WriteLine("Time taken for all loadings: {0} ms.", stopwatch.ElapsedMilliseconds); +``` diff --git a/pages/products/flexberry-orm/query-language/fo_psedodetails-linq-provider.ru.md b/pages/products/flexberry-orm/query-language/fo_psedodetails-linq-provider.ru.md index 991655e46..c3049380b 100644 --- a/pages/products/flexberry-orm/query-language/fo_psedodetails-linq-provider.ru.md +++ b/pages/products/flexberry-orm/query-language/fo_psedodetails-linq-provider.ru.md @@ -12,7 +12,7 @@ lang: ru Пусть сущности "Клиент" и "Кредит" связаны представленным на изображении образом. -![](/images/pages/products/flexberry-orm/query-language/pseudo-details.png) +![pseudo-details](/images/pages/products/flexberry-orm/query-language/pseudo-details.png) Нужно ограничить клиентов, задав при этом ограничение на ссылающихся на них кредиты. Специфика данной задачи состоит в том, что согласно модели клиент не знает, какие кредиты на него ссылаются. @@ -21,7 +21,9 @@ lang: ru Пусть: ```csharp -var ds = (SQLDataService)DataServiceProvider.DataService; +IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. +IDataService ds = mainUnityContainer.Resolve(); +SQLDataService sqldataservice = (SQLDataService)ds; ``` Задание ограничение на псевдодетейлы чуть менее интуитивно, чем использование [других возможностей LinqProvider](fo_linq-provider-faetures.html). @@ -39,8 +41,8 @@ var ds = (SQLDataService)DataServiceProvider.DataService; /// Представление псевдодетейла. /// Имя связи от псевдодетейла к мастеру. public PseudoDetail( - ICSSoft.STORMNET.View view, - string masterLinkName) + ICSSoft.STORMNET.View view, + string masterLinkName) ``` ```csharp @@ -50,8 +52,8 @@ public PseudoDetail( /// Представление псевдодетейла. /// Метод, определяющий имя связи от псевдодетейла к мастеру (определение идёт через "Information.ExtractPropertyPath(masterLink)"). public PseudoDetail( - ICSSoft.STORMNET.View view, - Expression> masterLink) + ICSSoft.STORMNET.View view, + Expression> masterLink) ``` ```csharp @@ -60,7 +62,7 @@ public PseudoDetail( /// /// Представление детейла. public PseudoDetail( - ICSSoft.STORMNET.View view) + ICSSoft.STORMNET.View view) ``` ```csharp @@ -71,9 +73,9 @@ public PseudoDetail( /// Метод, определяющий имя связи от псевдодетейла к мастеру (определение идёт через "Information.ExtractPropertyPath(masterLink)"). /// Имя связи от мастера к псевдодетейлу (псевдосвойство). public PseudoDetail( - ICSSoft.STORMNET.View view, - Expression> masterLink, - string masterToDetailPseudoProperty) + ICSSoft.STORMNET.View view, + Expression> masterLink, + string masterToDetailPseudoProperty) ``` ```csharp @@ -85,10 +87,10 @@ public PseudoDetail( /// Имя связи от мастера к псевдодетейлу (псевдосвойство). /// Свойства мастера, по которым можно произвести соединение. Аналог OwnerConnectProp для в lcs. public PseudoDetail( - ICSSoft.STORMNET.View view, - Expression> masterLink, - string masterToDetailPseudoProperty, - string[] masterConnectProperties) + ICSSoft.STORMNET.View view, + Expression> masterLink, + string masterToDetailPseudoProperty, + string[] masterConnectProperties) ``` ```csharp @@ -99,9 +101,9 @@ public PseudoDetail( /// Имя связи от псевдодетейла к мастеру. /// Имя связи от мастера к псевдодетейлу (псевдосвойство). public PseudoDetail( - ICSSoft.STORMNET.View view, - string masterLinkName, - string masterToDetailPseudoProperty) + ICSSoft.STORMNET.View view, + string masterLinkName, + string masterToDetailPseudoProperty) ``` ```csharp @@ -113,10 +115,10 @@ public PseudoDetail( /// Имя связи от мастера к псевдодетейлу (псевдосвойство). /// Свойства мастера, по которым можно произвести соединение. Аналог OwnerConnectProp для в lcs. public PseudoDetail( - ICSSoft.STORMNET.View view, - string masterLinkName, - string masterToDetailPseudoProperty, - string[] masterConnectProperties) + ICSSoft.STORMNET.View view, + string masterLinkName, + string masterToDetailPseudoProperty, + string[] masterConnectProperties) ``` ### Методы `PseudoDetail` @@ -155,40 +157,36 @@ public bool All(Expression> predicate) ```csharp var pseudoDetail = new PseudoDetail<Порода, Кошка>( - Information.GetView("КошкаE", typeof(Кошка)), - Information.ExtractPropertyPath<Кошка>(x => x.Порода)); + Information.GetView("КошкаE", typeof(Кошка)), + Information.ExtractPropertyPath<Кошка>(x => x.Порода)); // Все породы, для которых определены кошки -ds.Query<Порода>(Порода.Views.ПородаE).Where( - y => pseudoDetail.Any()).ToList(); +sqldataservice.Query<Порода>(Порода.Views.ПородаE).Where( + y => pseudoDetail.Any()).ToList(); ``` **Объект типа `PseudoDetail` определяется внутри linq-выражения:** ```csharp // Все породы, для которых определены кошки, у которых кличка не "Барсик" -ds.Query<Порода>(Порода.Views.ПородаE) - .Where( - y => - new PseudoDetail<Порода, Кошка>( - Information.GetView("КошкаE", typeof(Кошка)), - Information.ExtractPropertyPath<Кошка>(x => x.Порода)) - .Any(x.Кличка != "Барсик")) - .ToList(); +sqldataservice.Query<Порода>(Порода.Views.ПородаE).Where( + y => + new PseudoDetail<Порода, Кошка>( + Information.GetView("КошкаE", typeof(Кошка)), + Information.ExtractPropertyPath<Кошка>(x => x.Порода)) + .Any(x.Кличка != "Барсик")).ToList(); ``` #### Ограничение всеобщности на псевдодетейлы ```csharp // Все породы, где кошки не носят кличку "Барсик" -ds.Query<Порода>(Порода.Views.ПородаE) - .Where( - y => - new PseudoDetail<Порода, Кошка>( - Information.GetView("КошкаE", typeof(Кошка)), - Information.ExtractPropertyPath<Кошка>(x => x.Порода)) - .All(x.Кличка != "Барсик")) - .ToList(); +sqldataservice.Query<Порода>(Порода.Views.ПородаE).Where( + y => + new PseudoDetail<Порода, Кошка>( + Information.GetView("КошкаE", typeof(Кошка)), + Information.ExtractPropertyPath<Кошка>(x => x.Порода)) + .All(x.Кличка != "Барсик")).ToList(); ``` ## PseudoDetail и DetailVariableDef @@ -202,15 +200,15 @@ const string masterToDetailPropertyName = "SomePropertyName"; var masterConnectProperties = new string[] { "Property1", "Property2" }; ComparePseudoDetailWithDetailVariableDef( - new PseudoDetail<Порода, Кошка>( - Information.GetView("КошкаE", typeof(Кошка)), - Information.ExtractPropertyPath<Кошка>(x => x.Порода), - masterToDetailPropertyName, - masterConnectProperties), - new DetailVariableDef( - this.ldef.GetObjectType("Details"), - masterToDetailPropertyName, - Information.GetView("КошкаE", typeof(Кошка)), - "Порода", - masterConnectProperties)); + new PseudoDetail<Порода, Кошка>( + Information.GetView("КошкаE", typeof(Кошка)), + Information.ExtractPropertyPath<Кошка>(x => x.Порода), + masterToDetailPropertyName, + masterConnectProperties), + new DetailVariableDef( + this.ldef.GetObjectType("Details"), + masterToDetailPropertyName, + Information.GetView("КошкаE", typeof(Кошка)), + "Порода", + masterConnectProperties)); ``` diff --git a/pages/products/flexberry-orm/query-language/fo_restriction-datetime.ru.md b/pages/products/flexberry-orm/query-language/fo_restriction-datetime.ru.md index 921a8b1eb..7fde699e7 100644 --- a/pages/products/flexberry-orm/query-language/fo_restriction-datetime.ru.md +++ b/pages/products/flexberry-orm/query-language/fo_restriction-datetime.ru.md @@ -16,7 +16,9 @@ lang: ru В примерах ниже будем использовать следующий код: ```csharp -var langdef = ExternalLangDef.LanguageDef; +IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. +IDataService ds = mainUnityContainer.Resolve(); +ExternalLangDef languageDef = new ExternalLangDef(ds); var order = LoadingCustomizationStruct.GetSimpleStruct(typeof (Заказ), Заказ.Views.ЗаказL); ``` diff --git a/pages/products/flexberry-orm/query-language/fo_using-languagedef.ru.md b/pages/products/flexberry-orm/query-language/fo_using-languagedef.ru.md index c19a88b15..1c63a3261 100644 --- a/pages/products/flexberry-orm/query-language/fo_using-languagedef.ru.md +++ b/pages/products/flexberry-orm/query-language/fo_using-languagedef.ru.md @@ -1,602 +1,602 @@ ---- -title: Создание собственных функций при использовании LanguageDef -sidebar: flexberry-orm_sidebar -keywords: Flexberry ORM, Ограничения -summary: Разработка языка задания ограничений -toc: true -permalink: ru/fo_using-languagedef.html -lang: ru ---- - -Существуют стандартные "построители" функций для наложения ограничений, [SQLWhereLanguageDef](fo_function-list.html) и [ExternalLangDef](fo_external-lang-def.html). -Создание собственных функций при использовании LanguageDef (языка задания ограничений) позволяет создавать СУБД-независимые конструкции и использовать из для ограничения через [FunctionalLanguage](fo_limit-function.html) или рукописные скрипты. Использование этого подхода позволяет создавать более лёгкий в сопровождении код, нежели написание дублирующих выражений для каждой СУБД. - -{% include important.html content="Пользовательские функции должны начинаться с символов `user_`!. "%} - -### Пример - -Разработка языка задания ограничений ExportLanguage, работа с которым будет производиться следующим образом: - -```csharp -// Создание экземпляра языка. -ExportLanguage langForExport = new ExportLanguage(this.DataService); -ICSSoft.STORMNET.Windows.Forms.ExternalLangDef myLangDef = langForExport.Language; -myLangDef.GetFunction("user_LPAD_SPACE", langForExport.q("Т.НомерКУСП"), 8) -myLangDef.GetFunction("user_Day", langForExport.q("Т.ВремяЗаполнения")) -``` - -Класс `ExternalLangDef` не позволяет в одном экземпляре содержать предопределённые функции и заданные руками, поэтому приходится использовать 2 экземпляра языка (экземпляры ничем не отличаются, за исключением функций, которые используют для записи выражений): - -* new ExternalLangDef() -* (new ExportLanguage()).Language. - -`Функция q` носит вспомогательный характер, и не является частью подхода. Она, для удобства создания кода большого объёма, разделяет идентификатор, содержащий точки, на несколько идентификаторов, идущих через точку. - -```csharp -using ICSSoft.STORMNET.UI; -using ICSSoft.STORMNET.Business; -using ICSSoft.STORMNET.FunctionalLanguage; -using ICSSoft.STORMNET.FunctionalLanguage.SQLWhere; -using System.Collections; -   -public class ExportLanguage -{ -    /// -    /// DataService для конкретной СУБД. -    /// -    private IDataService DataService; -      -    /// -    /// Конструктор, котрый требует определения сервиса конкретной СУБД. -    /// -    /// -    public ExportLanguage(IDataService dataService) -    { -        DataService = dataService; -    } -      -    /// -    /// Создаёт экземпляр языка, содержащего заданные функции (и только их) -    /// -    public ICSSoft.STORMNET.Windows.Forms.ExternalLangDef Language -    { -        get -        { -            ICSSoft.STORMNET.Windows.Forms.ExternalLangDef myLangDef = new ICSSoft.STORMNET.Windows.Forms.ExternalLangDef(); -            TuneUp_Language(myLangDef); -            return myLangDef; -        } -    } -      -    /// -    /// Настройка языка (при этом стандартные возможности отбрасываются) -    /// -    /// Экземпляр языка для настройки -    public void TuneUp_Language(ICSSoft.STORMNET.Windows.Forms.ExternalLangDef langdef) -    { -        langdef.UserSQLTranslFunction = new ICSSoft.STORMNET.Windows.Forms.ExternalLangDef.delegateUserSQLTranslFunction(SQLTranslFunction); -        CreateNewLimitFunctions(langdef); -    } -      -    /// -    /// Определение функций языка (стандартные функции станут невозможными) -    /// -    /// -    public void CreateNewLimitFunctions(ICSSoft.STORMNET.Windows.Forms.ExternalLangDef langdef) -    { -        string funcName = string.Empty; -        FunctionDef funcDef = null; -          -        // для получения FuncID -        // FuncID - идентификатор функции в языке. -        // Стандартные функции имеют номера, начиная с единицы, и увеличиваются в порядке возрастнания числа. -        // Поэтому, чтобы не использовать занятые номера, будет отсчитывать сверху вниз от максимального значения. -        int i = int.MaxValue - 1; -        ArrayList ar; -          -        #region CHARINDEX -            ar = new ArrayList(); -            funcName = "user_CHARINDEX"; -            funcDef = new ICSSoft.STORMNET.FunctionalLanguage.FunctionDef( -                            i--, -                            langdef.NumericType, -                            funcName, -                            "Позиция символа в строке", -                            null, -                            "(Позиция символа ({0}) в строке {1})", -                            new ICSSoft.STORMNET.FunctionalLanguage.FunctionParameterDef(langdef.StringType), -                            new ICSSoft.STORMNET.FunctionalLanguage.FunctionParameterDef(langdef.StringType)); -            funcDef.Language = langdef; -            ar.Add(funcDef); -            langdef.FunctionsByStringedViewList.Add(funcName, ar); -        #endregion -          -        #region LTRIM -            ar = new ArrayList(); -            funcName = "user_LTRIM"; -            funcDef = new ICSSoft.STORMNET.FunctionalLanguage.FunctionDef( -                            i--, -                            langdef.StringType, -                            funcName, -                            "Отсечение пробелов слева", -                            null, -                            "(Отсечение пробелов слева({0}))", -                            new ICSSoft.STORMNET.FunctionalLanguage.FunctionParameterDef(langdef.StringType)); -            funcDef.Language = langdef; -            ar.Add(funcDef); -            langdef.FunctionsByStringedViewList.Add(funcName, ar); -        #endregion -          -        #region LEFT -            ar = new ArrayList(); -            funcName = "user_LEFT"; -            funcDef = new ICSSoft.STORMNET.FunctionalLanguage.FunctionDef( -                            i--, -                            langdef.StringType, -                            funcName, -                            "Урезание длины строки", -                            null, -                            "(Урезание длины строки({0}))", -                            new ICSSoft.STORMNET.FunctionalLanguage.FunctionParameterDef(langdef.StringType)); -            funcDef.Language = langdef; -            ar.Add(funcDef); -            langdef.FunctionsByStringedViewList.Add(funcName, ar); -        #endregion -          -        #region LEN -            ar = new ArrayList(); -            funcName = "user_LEN"; -            funcDef = new ICSSoft.STORMNET.FunctionalLanguage.FunctionDef( -                            i--, -                            langdef.NumericType, -                            funcName, -                            "Длина строки", -                            null, -                            "(Длина строки({0}))", -                            new ICSSoft.STORMNET.FunctionalLanguage.FunctionParameterDef(langdef.StringType)); -            funcDef.Language = langdef; -            ar.Add(funcDef); -            langdef.FunctionsByStringedViewList.Add(funcName, ar); -        #endregion -          -        #region CAST_AS_NUMERIC -            ar = new ArrayList(); -            funcName = "user_CAST_AS_NUMERIC"; -            funcDef = new ICSSoft.STORMNET.FunctionalLanguage.FunctionDef( -                            i--, -                            langdef.NumericType, -                            funcName, -                            string.Empty, -                            null, -                            string.Empty, -                            new ICSSoft.STORMNET.FunctionalLanguage.FunctionParameterDef(langdef.StringType)); -            funcDef.Language = langdef; -            ar.Add(funcDef); -            langdef.FunctionsByStringedViewList.Add(funcName, ar); -        #endregion -          -        #region Day -            ar = new ArrayList(); -            funcName = "user_Day"; -            funcDef = new ICSSoft.STORMNET.FunctionalLanguage.FunctionDef( -                            i--, -                            langdef.NumericType, -                            funcName, -                            string.Empty, -                            null, -                            string.Empty, -                            new ICSSoft.STORMNET.FunctionalLanguage.FunctionParameterDef(langdef.StringType)); -            funcDef.Language = langdef; -            ar.Add(funcDef); -            langdef.FunctionsByStringedViewList.Add(funcName, ar); -        #endregion -          -        #region Month -            ar = new ArrayList(); -            funcName = "user_Month"; -            funcDef = new ICSSoft.STORMNET.FunctionalLanguage.FunctionDef( -                            i--, -                            langdef.NumericType, -                            funcName, -                            string.Empty, -                            null, -                            string.Empty, -                            new ICSSoft.STORMNET.FunctionalLanguage.FunctionParameterDef(langdef.StringType)); -            funcDef.Language = langdef; -            ar.Add(funcDef); -            langdef.FunctionsByStringedViewList.Add(funcName, ar); -        #endregion -          -        #region Year -            ar = new ArrayList(); -            funcName = "user_Year"; -            funcDef = new ICSSoft.STORMNET.FunctionalLanguage.FunctionDef( -                            i--, -                            langdef.NumericType, -                            funcName, -                            string.Empty, -                            null, -                            string.Empty, -                            new ICSSoft.STORMNET.FunctionalLanguage.FunctionParameterDef(langdef.StringType)); -            funcDef.Language = langdef; -            ar.Add(funcDef); -            langdef.FunctionsByStringedViewList.Add(funcName, ar); -        #endregion -          -        #region Hour -            ar = new ArrayList(); -            funcName = "user_Hour"; -            funcDef = new ICSSoft.STORMNET.FunctionalLanguage.FunctionDef( -                            i--, -                            langdef.NumericType, -                            funcName, -                            string.Empty, -                            null, -                            string.Empty, -                            new ICSSoft.STORMNET.FunctionalLanguage.FunctionParameterDef(langdef.StringType)); -            funcDef.Language = langdef; -            ar.Add(funcDef); -            langdef.FunctionsByStringedViewList.Add(funcName, ar); -        #endregion -          -        #region Minute -            ar = new ArrayList(); -            funcName = "user_Minute"; -            funcDef = new ICSSoft.STORMNET.FunctionalLanguage.FunctionDef( -                            i--, -                            langdef.NumericType, -                            funcName, -                            string.Empty, -                            null, -                            string.Empty, -                            new ICSSoft.STORMNET.FunctionalLanguage.FunctionParameterDef(langdef.StringType)); -            funcDef.Language = langdef; -            ar.Add(funcDef); -            langdef.FunctionsByStringedViewList.Add(funcName, ar); -        #endregion -          -        #region LPAD_SPACE -            ar = new ArrayList(); -            funcName = "user_LPAD_SPACE"; -            funcDef = new ICSSoft.STORMNET.FunctionalLanguage.FunctionDef( -                            i--, -                            langdef.StringType, -                            funcName, -                            "", -                            null, -                            "", -                            new ICSSoft.STORMNET.FunctionalLanguage.FunctionParameterDef(langdef.StringType), -                            new ICSSoft.STORMNET.FunctionalLanguage.FunctionParameterDef(langdef.NumericType)); -            funcDef.Language = langdef; -            ar.Add(funcDef); -            langdef.FunctionsByStringedViewList.Add(funcName, ar); -        #endregion -          -        #region CONVERT_DECIMAL -            ar = new ArrayList(); -            funcName = "user_CONVERT_DECIMAL"; -            funcDef = new ICSSoft.STORMNET.FunctionalLanguage.FunctionDef( -                            i--, -                            langdef.StringType, -                            funcName, -                            "", -                            null, -                            "", -                            new ICSSoft.STORMNET.FunctionalLanguage.FunctionParameterDef(langdef.NumericType), -                            new ICSSoft.STORMNET.FunctionalLanguage.FunctionParameterDef(langdef.NumericType)); -            funcDef.Language = langdef; -            ar.Add(funcDef); -            langdef.FunctionsByStringedViewList.Add(funcName, ar); -        #endregion -          -        #region ISNULL -            ar = new ArrayList(); -            funcName = "user_ISNULL"; -            funcDef = new ICSSoft.STORMNET.FunctionalLanguage.FunctionDef( -                            i--, -                            langdef.StringType, -                            funcName, -                            "", -                            null, -                            "", -                            new ICSSoft.STORMNET.FunctionalLanguage.FunctionParameterDef(langdef.StringType), -                            new ICSSoft.STORMNET.FunctionalLanguage.FunctionParameterDef(langdef.StringType)); -            funcDef.Language = langdef; -            ar.Add(funcDef); -            langdef.FunctionsByStringedViewList.Add(funcName, ar); -        #endregion -    } -      -    /// -    /// Определяем подстановки -    /// -    /// -    /// -    /// -    /// -    string SQLTranslFunction(ICSSoft.STORMNET.FunctionalLanguage.Function func, -    ICSSoft.STORMNET.FunctionalLanguage.SQLWhere.delegateConvertValueToQueryValueString convertValue, -    ICSSoft.STORMNET.FunctionalLanguage.SQLWhere.delegatePutIdentifierToBrackets convertIdentifier) -    { -        string result = string.Empty; -          -        #region CHARINDEX -            if (func.FunctionDef.StringedView == "user_CHARINDEX") -            { -                if (this.DataService is ICSSoft.STORMNET.Business.MSSQLDataService) -                { -                    result = string.Format("CHARINDEX({0}, {1})", func.Parameters[0].ToString(), func.Parameters[1].ToString()); -                } -                  -                if (this.DataService is ICSSoft.STORMNET.Business.OracleDataService) -                { -                    result = string.Format("INSTR({0}, {1}, 1, 1 )", func.Parameters[0].ToString(), func.Parameters[1].ToString()); -                } -                  -                return result; -            } -        #endregion -          -        #region LTRIM -            if (func.FunctionDef.StringedView == "user_LTRIM") -            { -                if (this.DataService is ICSSoft.STORMNET.Business.MSSQLDataService) -                { -                    result = string.Format("LTRIM({0})", func.Parameters[0].ToString()); -                } -                  -                if (this.DataService is ICSSoft.STORMNET.Business.OracleDataService) -                { -                    result = string.Format("LTRIM({0})", func.Parameters[0].ToString()); -                } -                  -                return result; -            } -        #endregion -          -        #region LEFT -            if (func.FunctionDef.StringedView == "user_LEFT") -            { -                if (this.DataService is ICSSoft.STORMNET.Business.MSSQLDataService) -                { -                    result = string.Format("LEFT({0}, {1})", func.Parameters[0].ToString(), func.Parameters[1].ToString()); -                } -                  -                if (this.DataService is ICSSoft.STORMNET.Business.OracleDataService) -                { -                    result = string.Format("SUBSTR({0}, 0, {1})", func.Parameters[0].ToString(), func.Parameters[1].ToString()); -                } -                  -                return result; -            } -        #endregion -          -        #region LEN -            if (func.FunctionDef.StringedView == "user_LEN") -            { -                if (this.DataService is ICSSoft.STORMNET.Business.MSSQLDataService) -                { -                    result = string.Format("LEN({0})", func.Parameters[0].ToString()); -                } -                  -                if (this.DataService is ICSSoft.STORMNET.Business.OracleDataService) -                { -                    result = string.Format("LENGTH({0})", func.Parameters[0].ToString()); -                } -                  -                return result; -            } -        #endregion -          -        #region CAST AS NUMERIC -            if (func.FunctionDef.StringedView == "user_CAST_AS_NUMERIC") -            { -                // у меня на компе так: в SQL Server разделитель точка, в Oracle - запятая -                if (this.DataService is ICSSoft.STORMNET.Business.MSSQLDataService) -                { -                    // REPLACE(',', '.') -                    result = string.Format("CAST({0} AS NUMERIC)", func.Parameters[0].ToString()); -                } -                  -                if (this.DataService is ICSSoft.STORMNET.Business.OracleDataService) -                { -                    // REPLACE('.', ',') -                    result = string.Format("TO_NUMBER({0})", func.Parameters[0].ToString()); -                } -                  -                return result; -            } -        #endregion -          -        #region Day -            if (func.FunctionDef.StringedView == "user_Day") -            { -                ICSSoft.STORMNET.Windows.Forms.ExternalLangDef langdef = new ICSSoft.STORMNET.Windows.Forms.ExternalLangDef(); -                if (this.DataService is ICSSoft.STORMNET.Business.MSSQLDataService) -                { -                    result = string.Format( -                        "CASE WHEN {0} < 10 AND {0} >= 0 THEN '0' + CONVERT(VARCHAR, {0}) ELSE CONVERT(VARCHAR, {0}) END", -                        (DataService as SQLDataService).LimitFunction2SQLWhere( -                            langdef.GetFunction(langdef.funcDayPart, new VariableDef(langdef.DateTimeType, RemoveFrameq(func.Parameters[0].ToString()))))); -                } -                  -                if (this.DataService is ICSSoft.STORMNET.Business.OracleDataService) -                { -                    result = string.Format( -                        "LPAD(TO_CHAR({0}), 2, '0')", -                        (DataService as SQLDataService).LimitFunction2SQLWhere( -                            langdef.GetFunction(langdef.funcDayPart, new VariableDef(langdef.DateTimeType, RemoveFrameq(func.Parameters[0].ToString()))))); -                } -                  -                return result; -            } -        #endregion -          -        #region Month -            if (func.FunctionDef.StringedView == "user_Month") -            { -                ICSSoft.STORMNET.Windows.Forms.ExternalLangDef langdef = new ICSSoft.STORMNET.Windows.Forms.ExternalLangDef(); -                if (this.DataService is ICSSoft.STORMNET.Business.MSSQLDataService) -                { -                    result = string.Format( -                                "CASE WHEN {0} < 10 AND {0} >= 0 THEN '0' + CONVERT(VARCHAR, {0}) ELSE CONVERT(VARCHAR, {0}) END", -                                (DataService as SQLDataService).LimitFunction2SQLWhere( -                                    langdef.GetFunction(langdef.funcMonthPart, new VariableDef(langdef.DateTimeType, RemoveFrameq(func.Parameters[0].ToString()))))); -                } -                if (this.DataService is ICSSoft.STORMNET.Business.OracleDataService) -                { -                    result = string.Format( -                                "LPAD(TO_CHAR({0}), 2, '0')", -                                (DataService as SQLDataService).LimitFunction2SQLWhere( -                                    langdef.GetFunction(langdef.funcMonthPart, new VariableDef(langdef.DateTimeType, RemoveFrameq(func.Parameters[0].ToString()))))); -                } -                return result; -            } -        #endregion -          -        #region Year -            if (func.FunctionDef.StringedView == "user_Year") -            { -                ICSSoft.STORMNET.Windows.Forms.ExternalLangDef langdef = new ICSSoft.STORMNET.Windows.Forms.ExternalLangDef(); -                result = (DataService as SQLDataService).LimitFunction2SQLWhere( -                                langdef.GetFunction(langdef.funcYearPart, new VariableDef(langdef.DateTimeType, RemoveFrameq(func.Parameters[0].ToString())))); -                return result; -            } -        #endregion -          -        #region Hour -            if (func.FunctionDef.StringedView == "user_Hour") -            { -                ICSSoft.STORMNET.Windows.Forms.ExternalLangDef langdef = new ICSSoft.STORMNET.Windows.Forms.ExternalLangDef(); -                if (this.DataService is ICSSoft.STORMNET.Business.MSSQLDataService) -                { -                    result = string.Format( -                        "CASE WHEN {0} < 10 AND {0} >= 0 THEN '0' + CONVERT(VARCHAR, {0}) ELSE CONVERT(VARCHAR, {0}) END", -                        (DataService as SQLDataService).LimitFunction2SQLWhere( -                            langdef.GetFunction(langdef.funcHHPart, new VariableDef(langdef.DateTimeType, RemoveFrameq(func.Parameters[0].ToString()))))); -                } -                  -                if (this.DataService is ICSSoft.STORMNET.Business.OracleDataService) -                { -                    result = string.Format( -                        "LPAD(TO_CHAR({0}), 2, '0')", -                        (DataService as SQLDataService).LimitFunction2SQLWhere( -                            langdef.GetFunction(langdef.funcHHPart, new VariableDef(langdef.DateTimeType, RemoveFrameq(func.Parameters[0].ToString()))))); -                } -                  -                return result; -            } -        #endregion -          -        #region Minute -            if (func.FunctionDef.StringedView == "user_Minute") -            { -                ICSSoft.STORMNET.Windows.Forms.ExternalLangDef langdef = new ICSSoft.STORMNET.Windows.Forms.ExternalLangDef(); -                if (this.DataService is ICSSoft.STORMNET.Business.MSSQLDataService) -                { -                    result = string.Format( -                        "CASE WHEN {0} < 10 AND {0} >= 0 THEN '0' + CONVERT(VARCHAR, {0}) ELSE CONVERT(VARCHAR, {0}) END", -                        (DataService as SQLDataService).LimitFunction2SQLWhere( -                            langdef.GetFunction(langdef.funcMIPart, new VariableDef(langdef.DateTimeType, RemoveFrameq(func.Parameters[0].ToString()))))); -                } -                  -                if (this.DataService is ICSSoft.STORMNET.Business.OracleDataService) -                { -                    result = string.Format( -                        "LPAD(TO_CHAR({0}), 2, '0')", -                        (DataService as SQLDataService).LimitFunction2SQLWhere( -                            langdef.GetFunction(langdef.funcMIPart, new VariableDef(langdef.DateTimeType, RemoveFrameq(func.Parameters[0].ToString()))))); -                } -                  -                return result; -            } -        #endregion -          -        #region LPAD_SPACE -            if (func.FunctionDef.StringedView == "user_LPAD_SPACE") -            { -                if (this.DataService is ICSSoft.STORMNET.Business.MSSQLDataService) -                { -                    result = string.Format("RIGHT (SPACE({1}) + CONVERT(VARCHAR({1}), {0}), {1} )", func.Parameters[0].ToString(), func.Parameters[1].ToString()); -                } -                  -                if (this.DataService is ICSSoft.STORMNET.Business.OracleDataService) -                { -                    result = string.Format("LPAD({0}, {1})", func.Parameters[0].ToString(), func.Parameters[1].ToString()); -                } -                  -                return result; -            } -        #endregion -          -        #region CONVERT_DECIMAL -            if (func.FunctionDef.StringedView == "user_CONVERT_DECIMAL") -            { -                if (this.DataService is ICSSoft.STORMNET.Business.MSSQLDataService) -                { -                    result = string.Format( -                        "CASE WHEN {0} > REPLICATE('9', {1} - 2 - 1) + '.99' THEN LEFT ( SUBSTRING ( CONVERT(VARCHAR( 31 ), {0} ), 1, CHARINDEX ('.', CONVERT(VARCHAR( 31 ), {0} )) - 1), {1} ) ELSE LEFT ( CONVERT(VARCHAR( 31 ), {0} ), {1} ) END", -                        func.Parameters[0].ToString(), func.Parameters[1].ToString()); -                } -                  -                if (this.DataService is ICSSoft.STORMNET.Business.OracleDataService) -                { -                    result = string.Format( -                        "CASE WHEN {0} > RPAD('9', {1} - 2 - 1, '9') + ',99' THEN RPAD ( SUBSTR ( TO_CHAR({0}), 1, INSTR ('.', TO_CHAR({0}), 1, 1) - 1), {1} ) ELSE RPAD ( TO_CHAR({0}), {1} ) END", -                        func.Parameters[0].ToString(), func.Parameters[1].ToString()); -                } -                  -                return result; -            } -        #endregion -          -        #region ISNULL -            if (func.FunctionDef.StringedView == "user_ISNULL") -            { -                if (this.DataService is ICSSoft.STORMNET.Business.MSSQLDataService) -                { -                    result = string.Format("ISNULL({0}, {1})", func.Parameters[0].ToString(), func.Parameters[1].ToString()); -                } -                if (this.DataService is ICSSoft.STORMNET.Business.OracleDataService) -                { -                    result = string.Format("NVL({0}, {1})", func.Parameters[0].ToString(), func.Parameters[1].ToString()); -                } -                return result; -            } -        #endregion -        return result; -    } -      -    /// -    /// Преобразует СУБД-независимую структуру Function в строку запроса для конкретной СУБД -    /// -    /// -    /// -    public string ParseLimitFunction(Function func) -    { -        return (this.DataService as SQLDataService).LimitFunction2SQLWhere(func); -    } -      -    /// -    /// Краткая запись для SQLDataService.PutIdentifierIntoBrackets -    /// -    /// -    /// -    public string q(string ident) -    { -        string s = ident; -        if (ident.IndexOf("\".\"") == -1 && ident.IndexOf(".") != 0) -        { -            s = ident.Replace(".", "\".\""); -        } -          -        return (DataService as SQLDataService).PutIdentifierIntoBrackets(s); -    } -       -    public string RemoveFrameq(string ident) -    { -        return ident.TrimStart('"').TrimEnd('"'); -    } -} - -``` +--- +title: Создание собственных функций при использовании LanguageDef +sidebar: flexberry-orm_sidebar +keywords: Flexberry ORM, Ограничения +summary: Разработка языка задания ограничений +toc: true +permalink: ru/fo_using-languagedef.html +lang: ru +--- + +Существуют стандартные "построители" функций для наложения ограничений, [SQLWhereLanguageDef](fo_function-list.html) и [ExternalLangDef](fo_external-lang-def.html). +Создание собственных функций при использовании LanguageDef (языка задания ограничений) позволяет создавать СУБД-независимые конструкции и использовать из для ограничения через [FunctionalLanguage](fo_limit-function.html) или рукописные скрипты. Использование этого подхода позволяет создавать более лёгкий в сопровождении код, нежели написание дублирующих выражений для каждой СУБД. + +{% include important.html content="Пользовательские функции должны начинаться с символов `user_`!. "%} + +### Пример + +Разработка языка задания ограничений ExportLanguage, работа с которым будет производиться следующим образом: + +```csharp +// Создание экземпляра языка. +ExportLanguage langForExport = new ExportLanguage(this.DataService); +ICSSoft.STORMNET.Windows.Forms.ExternalLangDef myLangDef = langForExport.Language; +myLangDef.GetFunction("user_LPAD_SPACE", langForExport.q("Т.НомерКУСП"), 8) +myLangDef.GetFunction("user_Day", langForExport.q("Т.ВремяЗаполнения")) +``` + +Класс `ExternalLangDef` не позволяет в одном экземпляре содержать предопределённые функции и заданные руками, поэтому приходится использовать 2 экземпляра языка (экземпляры ничем не отличаются, за исключением функций, которые используют для записи выражений): + +* ExternalLangDef languageDef = new ExternalLangDef(ds) +* (new ExportLanguage()).Language. + +`Функция q` носит вспомогательный характер, и не является частью подхода. Она, для удобства создания кода большого объёма, разделяет идентификатор, содержащий точки, на несколько идентификаторов, идущих через точку. + +```csharp +using ICSSoft.STORMNET.UI; +using ICSSoft.STORMNET.Business; +using ICSSoft.STORMNET.FunctionalLanguage; +using ICSSoft.STORMNET.FunctionalLanguage.SQLWhere; +using System.Collections; +   +public class ExportLanguage +{ +    /// +    /// DataService для конкретной СУБД. +    /// +    private IDataService DataService; +      +    /// +    /// Конструктор, котрый требует определения сервиса конкретной СУБД. +    /// +    /// +    public ExportLanguage(IDataService dataService) +    { +        DataService = dataService; +    } +      +    /// +    /// Создаёт экземпляр языка, содержащего заданные функции (и только их) +    /// +    public ICSSoft.STORMNET.Windows.Forms.ExternalLangDef Language +    { +        get +        { +            ICSSoft.STORMNET.Windows.Forms.ExternalLangDef myLangDef = new ICSSoft.STORMNET.Windows.Forms.ExternalLangDef(); +            TuneUp_Language(myLangDef); +            return myLangDef; +        } +    } +      +    /// +    /// Настройка языка (при этом стандартные возможности отбрасываются) +    /// +    /// Экземпляр языка для настройки +    public void TuneUp_Language(ICSSoft.STORMNET.Windows.Forms.ExternalLangDef langdef) +    { +        langdef.UserSQLTranslFunction = new ICSSoft.STORMNET.Windows.Forms.ExternalLangDef.delegateUserSQLTranslFunction(SQLTranslFunction); +        CreateNewLimitFunctions(langdef); +    } +      +    /// +    /// Определение функций языка (стандартные функции станут невозможными) +    /// +    /// +    public void CreateNewLimitFunctions(ICSSoft.STORMNET.Windows.Forms.ExternalLangDef langdef) +    { +        string funcName = string.Empty; +        FunctionDef funcDef = null; +          +        // для получения FuncID +        // FuncID - идентификатор функции в языке. +        // Стандартные функции имеют номера, начиная с единицы, и увеличиваются в порядке возрастнания числа. +        // Поэтому, чтобы не использовать занятые номера, будет отсчитывать сверху вниз от максимального значения. +        int i = int.MaxValue - 1; +        ArrayList ar; +          +        #region CHARINDEX +            ar = new ArrayList(); +            funcName = "user_CHARINDEX"; +            funcDef = new ICSSoft.STORMNET.FunctionalLanguage.FunctionDef( +                            i--, +                            langdef.NumericType, +                            funcName, +                            "Позиция символа в строке", +                            null, +                            "(Позиция символа ({0}) в строке {1})", +                            new ICSSoft.STORMNET.FunctionalLanguage.FunctionParameterDef(langdef.StringType), +                            new ICSSoft.STORMNET.FunctionalLanguage.FunctionParameterDef(langdef.StringType)); +            funcDef.Language = langdef; +            ar.Add(funcDef); +            langdef.FunctionsByStringedViewList.Add(funcName, ar); +        #endregion +          +        #region LTRIM +            ar = new ArrayList(); +            funcName = "user_LTRIM"; +            funcDef = new ICSSoft.STORMNET.FunctionalLanguage.FunctionDef( +                            i--, +                            langdef.StringType, +                            funcName, +                            "Отсечение пробелов слева", +                            null, +                            "(Отсечение пробелов слева({0}))", +                            new ICSSoft.STORMNET.FunctionalLanguage.FunctionParameterDef(langdef.StringType)); +            funcDef.Language = langdef; +            ar.Add(funcDef); +            langdef.FunctionsByStringedViewList.Add(funcName, ar); +        #endregion +          +        #region LEFT +            ar = new ArrayList(); +            funcName = "user_LEFT"; +            funcDef = new ICSSoft.STORMNET.FunctionalLanguage.FunctionDef( +                            i--, +                            langdef.StringType, +                            funcName, +                            "Урезание длины строки", +                            null, +                            "(Урезание длины строки({0}))", +                            new ICSSoft.STORMNET.FunctionalLanguage.FunctionParameterDef(langdef.StringType)); +            funcDef.Language = langdef; +            ar.Add(funcDef); +            langdef.FunctionsByStringedViewList.Add(funcName, ar); +        #endregion +          +        #region LEN +            ar = new ArrayList(); +            funcName = "user_LEN"; +            funcDef = new ICSSoft.STORMNET.FunctionalLanguage.FunctionDef( +                            i--, +                            langdef.NumericType, +                            funcName, +                            "Длина строки", +                            null, +                            "(Длина строки({0}))", +                            new ICSSoft.STORMNET.FunctionalLanguage.FunctionParameterDef(langdef.StringType)); +            funcDef.Language = langdef; +            ar.Add(funcDef); +            langdef.FunctionsByStringedViewList.Add(funcName, ar); +        #endregion +          +        #region CAST_AS_NUMERIC +            ar = new ArrayList(); +            funcName = "user_CAST_AS_NUMERIC"; +            funcDef = new ICSSoft.STORMNET.FunctionalLanguage.FunctionDef( +                            i--, +                            langdef.NumericType, +                            funcName, +                            string.Empty, +                            null, +                            string.Empty, +                            new ICSSoft.STORMNET.FunctionalLanguage.FunctionParameterDef(langdef.StringType)); +            funcDef.Language = langdef; +            ar.Add(funcDef); +            langdef.FunctionsByStringedViewList.Add(funcName, ar); +        #endregion +          +        #region Day +            ar = new ArrayList(); +            funcName = "user_Day"; +            funcDef = new ICSSoft.STORMNET.FunctionalLanguage.FunctionDef( +                            i--, +                            langdef.NumericType, +                            funcName, +                            string.Empty, +                            null, +                            string.Empty, +                            new ICSSoft.STORMNET.FunctionalLanguage.FunctionParameterDef(langdef.StringType)); +            funcDef.Language = langdef; +            ar.Add(funcDef); +            langdef.FunctionsByStringedViewList.Add(funcName, ar); +        #endregion +          +        #region Month +            ar = new ArrayList(); +            funcName = "user_Month"; +            funcDef = new ICSSoft.STORMNET.FunctionalLanguage.FunctionDef( +                            i--, +                            langdef.NumericType, +                            funcName, +                            string.Empty, +                            null, +                            string.Empty, +                            new ICSSoft.STORMNET.FunctionalLanguage.FunctionParameterDef(langdef.StringType)); +            funcDef.Language = langdef; +            ar.Add(funcDef); +            langdef.FunctionsByStringedViewList.Add(funcName, ar); +        #endregion +          +        #region Year +            ar = new ArrayList(); +            funcName = "user_Year"; +            funcDef = new ICSSoft.STORMNET.FunctionalLanguage.FunctionDef( +                            i--, +                            langdef.NumericType, +                            funcName, +                            string.Empty, +                            null, +                            string.Empty, +                            new ICSSoft.STORMNET.FunctionalLanguage.FunctionParameterDef(langdef.StringType)); +            funcDef.Language = langdef; +            ar.Add(funcDef); +            langdef.FunctionsByStringedViewList.Add(funcName, ar); +        #endregion +          +        #region Hour +            ar = new ArrayList(); +            funcName = "user_Hour"; +            funcDef = new ICSSoft.STORMNET.FunctionalLanguage.FunctionDef( +                            i--, +                            langdef.NumericType, +                            funcName, +                            string.Empty, +                            null, +                            string.Empty, +                            new ICSSoft.STORMNET.FunctionalLanguage.FunctionParameterDef(langdef.StringType)); +            funcDef.Language = langdef; +            ar.Add(funcDef); +            langdef.FunctionsByStringedViewList.Add(funcName, ar); +        #endregion +          +        #region Minute +            ar = new ArrayList(); +            funcName = "user_Minute"; +            funcDef = new ICSSoft.STORMNET.FunctionalLanguage.FunctionDef( +                            i--, +                            langdef.NumericType, +                            funcName, +                            string.Empty, +                            null, +                            string.Empty, +                            new ICSSoft.STORMNET.FunctionalLanguage.FunctionParameterDef(langdef.StringType)); +            funcDef.Language = langdef; +            ar.Add(funcDef); +            langdef.FunctionsByStringedViewList.Add(funcName, ar); +        #endregion +          +        #region LPAD_SPACE +            ar = new ArrayList(); +            funcName = "user_LPAD_SPACE"; +            funcDef = new ICSSoft.STORMNET.FunctionalLanguage.FunctionDef( +                            i--, +                            langdef.StringType, +                            funcName, +                            "", +                            null, +                            "", +                            new ICSSoft.STORMNET.FunctionalLanguage.FunctionParameterDef(langdef.StringType), +                            new ICSSoft.STORMNET.FunctionalLanguage.FunctionParameterDef(langdef.NumericType)); +            funcDef.Language = langdef; +            ar.Add(funcDef); +            langdef.FunctionsByStringedViewList.Add(funcName, ar); +        #endregion +          +        #region CONVERT_DECIMAL +            ar = new ArrayList(); +            funcName = "user_CONVERT_DECIMAL"; +            funcDef = new ICSSoft.STORMNET.FunctionalLanguage.FunctionDef( +                            i--, +                            langdef.StringType, +                            funcName, +                            "", +                            null, +                            "", +                            new ICSSoft.STORMNET.FunctionalLanguage.FunctionParameterDef(langdef.NumericType), +                            new ICSSoft.STORMNET.FunctionalLanguage.FunctionParameterDef(langdef.NumericType)); +            funcDef.Language = langdef; +            ar.Add(funcDef); +            langdef.FunctionsByStringedViewList.Add(funcName, ar); +        #endregion +          +        #region ISNULL +            ar = new ArrayList(); +            funcName = "user_ISNULL"; +            funcDef = new ICSSoft.STORMNET.FunctionalLanguage.FunctionDef( +                            i--, +                            langdef.StringType, +                            funcName, +                            "", +                            null, +                            "", +                            new ICSSoft.STORMNET.FunctionalLanguage.FunctionParameterDef(langdef.StringType), +                            new ICSSoft.STORMNET.FunctionalLanguage.FunctionParameterDef(langdef.StringType)); +            funcDef.Language = langdef; +            ar.Add(funcDef); +            langdef.FunctionsByStringedViewList.Add(funcName, ar); +        #endregion +    } +      +    /// +    /// Определяем подстановки +    /// +    /// +    /// +    /// +    /// +    string SQLTranslFunction(ICSSoft.STORMNET.FunctionalLanguage.Function func, +    ICSSoft.STORMNET.FunctionalLanguage.SQLWhere.delegateConvertValueToQueryValueString convertValue, +    ICSSoft.STORMNET.FunctionalLanguage.SQLWhere.delegatePutIdentifierToBrackets convertIdentifier) +    { +        string result = string.Empty; +          +        #region CHARINDEX +            if (func.FunctionDef.StringedView == "user_CHARINDEX") +            { +                if (this.DataService is ICSSoft.STORMNET.Business.MSSQLDataService) +                { +                    result = string.Format("CHARINDEX({0}, {1})", func.Parameters[0].ToString(), func.Parameters[1].ToString()); +                } +                  +                if (this.DataService is ICSSoft.STORMNET.Business.OracleDataService) +                { +                    result = string.Format("INSTR({0}, {1}, 1, 1 )", func.Parameters[0].ToString(), func.Parameters[1].ToString()); +                } +                  +                return result; +            } +        #endregion +          +        #region LTRIM +            if (func.FunctionDef.StringedView == "user_LTRIM") +            { +                if (this.DataService is ICSSoft.STORMNET.Business.MSSQLDataService) +                { +                    result = string.Format("LTRIM({0})", func.Parameters[0].ToString()); +                } +                  +                if (this.DataService is ICSSoft.STORMNET.Business.OracleDataService) +                { +                    result = string.Format("LTRIM({0})", func.Parameters[0].ToString()); +                } +                  +                return result; +            } +        #endregion +          +        #region LEFT +            if (func.FunctionDef.StringedView == "user_LEFT") +            { +                if (this.DataService is ICSSoft.STORMNET.Business.MSSQLDataService) +                { +                    result = string.Format("LEFT({0}, {1})", func.Parameters[0].ToString(), func.Parameters[1].ToString()); +                } +                  +                if (this.DataService is ICSSoft.STORMNET.Business.OracleDataService) +                { +                    result = string.Format("SUBSTR({0}, 0, {1})", func.Parameters[0].ToString(), func.Parameters[1].ToString()); +                } +                  +                return result; +            } +        #endregion +          +        #region LEN +            if (func.FunctionDef.StringedView == "user_LEN") +            { +                if (this.DataService is ICSSoft.STORMNET.Business.MSSQLDataService) +                { +                    result = string.Format("LEN({0})", func.Parameters[0].ToString()); +                } +                  +                if (this.DataService is ICSSoft.STORMNET.Business.OracleDataService) +                { +                    result = string.Format("LENGTH({0})", func.Parameters[0].ToString()); +                } +                  +                return result; +            } +        #endregion +          +        #region CAST AS NUMERIC +            if (func.FunctionDef.StringedView == "user_CAST_AS_NUMERIC") +            { +                // у меня на компе так: в SQL Server разделитель точка, в Oracle - запятая +                if (this.DataService is ICSSoft.STORMNET.Business.MSSQLDataService) +                { +                    // REPLACE(',', '.') +                    result = string.Format("CAST({0} AS NUMERIC)", func.Parameters[0].ToString()); +                } +                  +                if (this.DataService is ICSSoft.STORMNET.Business.OracleDataService) +                { +                    // REPLACE('.', ',') +                    result = string.Format("TO_NUMBER({0})", func.Parameters[0].ToString()); +                } +                  +                return result; +            } +        #endregion +          +        #region Day +            if (func.FunctionDef.StringedView == "user_Day") +            { +                ICSSoft.STORMNET.Windows.Forms.ExternalLangDef langdef = new ICSSoft.STORMNET.Windows.Forms.ExternalLangDef(); +                if (this.DataService is ICSSoft.STORMNET.Business.MSSQLDataService) +                { +                    result = string.Format( +                        "CASE WHEN {0} < 10 AND {0} >= 0 THEN '0' + CONVERT(VARCHAR, {0}) ELSE CONVERT(VARCHAR, {0}) END", +                        (DataService as SQLDataService).LimitFunction2SQLWhere( +                            langdef.GetFunction(langdef.funcDayPart, new VariableDef(langdef.DateTimeType, RemoveFrameq(func.Parameters[0].ToString()))))); +                } +                  +                if (this.DataService is ICSSoft.STORMNET.Business.OracleDataService) +                { +                    result = string.Format( +                        "LPAD(TO_CHAR({0}), 2, '0')", +                        (DataService as SQLDataService).LimitFunction2SQLWhere( +                            langdef.GetFunction(langdef.funcDayPart, new VariableDef(langdef.DateTimeType, RemoveFrameq(func.Parameters[0].ToString()))))); +                } +                  +                return result; +            } +        #endregion +          +        #region Month +            if (func.FunctionDef.StringedView == "user_Month") +            { +                ICSSoft.STORMNET.Windows.Forms.ExternalLangDef langdef = new ICSSoft.STORMNET.Windows.Forms.ExternalLangDef(); +                if (this.DataService is ICSSoft.STORMNET.Business.MSSQLDataService) +                { +                    result = string.Format( +                                "CASE WHEN {0} < 10 AND {0} >= 0 THEN '0' + CONVERT(VARCHAR, {0}) ELSE CONVERT(VARCHAR, {0}) END", +                                (DataService as SQLDataService).LimitFunction2SQLWhere( +                                    langdef.GetFunction(langdef.funcMonthPart, new VariableDef(langdef.DateTimeType, RemoveFrameq(func.Parameters[0].ToString()))))); +                } +                if (this.DataService is ICSSoft.STORMNET.Business.OracleDataService) +                { +                    result = string.Format( +                                "LPAD(TO_CHAR({0}), 2, '0')", +                                (DataService as SQLDataService).LimitFunction2SQLWhere( +                                    langdef.GetFunction(langdef.funcMonthPart, new VariableDef(langdef.DateTimeType, RemoveFrameq(func.Parameters[0].ToString()))))); +                } +                return result; +            } +        #endregion +          +        #region Year +            if (func.FunctionDef.StringedView == "user_Year") +            { +                ICSSoft.STORMNET.Windows.Forms.ExternalLangDef langdef = new ICSSoft.STORMNET.Windows.Forms.ExternalLangDef(); +                result = (DataService as SQLDataService).LimitFunction2SQLWhere( +                                langdef.GetFunction(langdef.funcYearPart, new VariableDef(langdef.DateTimeType, RemoveFrameq(func.Parameters[0].ToString())))); +                return result; +            } +        #endregion +          +        #region Hour +            if (func.FunctionDef.StringedView == "user_Hour") +            { +                ICSSoft.STORMNET.Windows.Forms.ExternalLangDef langdef = new ICSSoft.STORMNET.Windows.Forms.ExternalLangDef(); +                if (this.DataService is ICSSoft.STORMNET.Business.MSSQLDataService) +                { +                    result = string.Format( +                        "CASE WHEN {0} < 10 AND {0} >= 0 THEN '0' + CONVERT(VARCHAR, {0}) ELSE CONVERT(VARCHAR, {0}) END", +                        (DataService as SQLDataService).LimitFunction2SQLWhere( +                            langdef.GetFunction(langdef.funcHHPart, new VariableDef(langdef.DateTimeType, RemoveFrameq(func.Parameters[0].ToString()))))); +                } +                  +                if (this.DataService is ICSSoft.STORMNET.Business.OracleDataService) +                { +                    result = string.Format( +                        "LPAD(TO_CHAR({0}), 2, '0')", +                        (DataService as SQLDataService).LimitFunction2SQLWhere( +                            langdef.GetFunction(langdef.funcHHPart, new VariableDef(langdef.DateTimeType, RemoveFrameq(func.Parameters[0].ToString()))))); +                } +                  +                return result; +            } +        #endregion +          +        #region Minute +            if (func.FunctionDef.StringedView == "user_Minute") +            { +                ICSSoft.STORMNET.Windows.Forms.ExternalLangDef langdef = new ICSSoft.STORMNET.Windows.Forms.ExternalLangDef(); +                if (this.DataService is ICSSoft.STORMNET.Business.MSSQLDataService) +                { +                    result = string.Format( +                        "CASE WHEN {0} < 10 AND {0} >= 0 THEN '0' + CONVERT(VARCHAR, {0}) ELSE CONVERT(VARCHAR, {0}) END", +                        (DataService as SQLDataService).LimitFunction2SQLWhere( +                            langdef.GetFunction(langdef.funcMIPart, new VariableDef(langdef.DateTimeType, RemoveFrameq(func.Parameters[0].ToString()))))); +                } +                  +                if (this.DataService is ICSSoft.STORMNET.Business.OracleDataService) +                { +                    result = string.Format( +                        "LPAD(TO_CHAR({0}), 2, '0')", +                        (DataService as SQLDataService).LimitFunction2SQLWhere( +                            langdef.GetFunction(langdef.funcMIPart, new VariableDef(langdef.DateTimeType, RemoveFrameq(func.Parameters[0].ToString()))))); +                } +                  +                return result; +            } +        #endregion +          +        #region LPAD_SPACE +            if (func.FunctionDef.StringedView == "user_LPAD_SPACE") +            { +                if (this.DataService is ICSSoft.STORMNET.Business.MSSQLDataService) +                { +                    result = string.Format("RIGHT (SPACE({1}) + CONVERT(VARCHAR({1}), {0}), {1} )", func.Parameters[0].ToString(), func.Parameters[1].ToString()); +                } +                  +                if (this.DataService is ICSSoft.STORMNET.Business.OracleDataService) +                { +                    result = string.Format("LPAD({0}, {1})", func.Parameters[0].ToString(), func.Parameters[1].ToString()); +                } +                  +                return result; +            } +        #endregion +          +        #region CONVERT_DECIMAL +            if (func.FunctionDef.StringedView == "user_CONVERT_DECIMAL") +            { +                if (this.DataService is ICSSoft.STORMNET.Business.MSSQLDataService) +                { +                    result = string.Format( +                        "CASE WHEN {0} > REPLICATE('9', {1} - 2 - 1) + '.99' THEN LEFT ( SUBSTRING ( CONVERT(VARCHAR( 31 ), {0} ), 1, CHARINDEX ('.', CONVERT(VARCHAR( 31 ), {0} )) - 1), {1} ) ELSE LEFT ( CONVERT(VARCHAR( 31 ), {0} ), {1} ) END", +                        func.Parameters[0].ToString(), func.Parameters[1].ToString()); +                } +                  +                if (this.DataService is ICSSoft.STORMNET.Business.OracleDataService) +                { +                    result = string.Format( +                        "CASE WHEN {0} > RPAD('9', {1} - 2 - 1, '9') + ',99' THEN RPAD ( SUBSTR ( TO_CHAR({0}), 1, INSTR ('.', TO_CHAR({0}), 1, 1) - 1), {1} ) ELSE RPAD ( TO_CHAR({0}), {1} ) END", +                        func.Parameters[0].ToString(), func.Parameters[1].ToString()); +                } +                  +                return result; +            } +        #endregion +          +        #region ISNULL +            if (func.FunctionDef.StringedView == "user_ISNULL") +            { +                if (this.DataService is ICSSoft.STORMNET.Business.MSSQLDataService) +                { +                    result = string.Format("ISNULL({0}, {1})", func.Parameters[0].ToString(), func.Parameters[1].ToString()); +                } +                if (this.DataService is ICSSoft.STORMNET.Business.OracleDataService) +                { +                    result = string.Format("NVL({0}, {1})", func.Parameters[0].ToString(), func.Parameters[1].ToString()); +                } +                return result; +            } +        #endregion +        return result; +    } +      +    /// +    /// Преобразует СУБД-независимую структуру Function в строку запроса для конкретной СУБД +    /// +    /// +    /// +    public string ParseLimitFunction(Function func) +    { +        return (this.DataService as SQLDataService).LimitFunction2SQLWhere(func); +    } +      +    /// +    /// Краткая запись для SQLDataService.PutIdentifierIntoBrackets +    /// +    /// +    /// +    public string q(string ident) +    { +        string s = ident; +        if (ident.IndexOf("\".\"") == -1 && ident.IndexOf(".") != 0) +        { +            s = ident.Replace(".", "\".\""); +        } +          +        return (DataService as SQLDataService).PutIdentifierIntoBrackets(s); +    } +       +    public string RemoveFrameq(string ident) +    { +        return ident.TrimStart('"').TrimEnd('"'); +    } +} + +``` diff --git a/pages/products/flexberry-orm/query-language/fo_variable-def.ru.md b/pages/products/flexberry-orm/query-language/fo_variable-def.ru.md index bf78ea215..84faa881d 100644 --- a/pages/products/flexberry-orm/query-language/fo_variable-def.ru.md +++ b/pages/products/flexberry-orm/query-language/fo_variable-def.ru.md @@ -84,9 +84,9 @@ ld.GetFunction(ld.funcEQ, new VariableDef(ld.GuidType, Information.ExtractProper Часто возникают сложности при определении, что указывать в качестве `ConnectMasterProp` и `OwnerConnectProp`. -`ConnectMasterProp` указывается путь от детейла, а в `OwnerConnectProp` - к детейлу от объекта. +`ConnectMasterProp` указывается путь от детейла, а в `OwnerConnectProp` - к детейлу от объекта. -Связка происходит следующим образом: **Детейл.ConnectMasterProp = Объект.OwnerConnectProp**. +Связка происходит следующим образом: **Детейл.ConnectMasterProp = Объект.OwnerConnectProp.** Cтоит отметить, что свойство `OwnerConnectProp` определяет, к какому объекту относятся детейлы. Если свойство не указано (т.е. указан `null`), то связка происходит по [первичному ключу](fo_primary-keys-objects.html)(т.е. по `StormMainObjectKey`). @@ -94,47 +94,49 @@ Cтоит отметить, что свойство `OwnerConnectProp` опре ##### Пример1 -![](/images/pages/products/flexberry-orm/query-language/diagramm.JPG) +![diagramm-2](/images/pages/products/flexberry-orm/diagramm-2.JPG) -Необходимо отфильтровать УдостоверяющиеДокументы для ЗаявленияАбитуриента. +Необходимо отфильтровать УдостоверяющиеДокументы для ЗаявленияАбитуриента. При задании `DetailVariableDef` следует указать: `OwnerConnectProp` = Личность, `ConnectMasterProp` = Личность. ##### Пример2 -![](/images/pages/products/flexberry-orm/query-language/diagramm-2.PNG) +![diagramm-2](/images/pages/products/flexberry-orm/query-language/diagramm-2.PNG) -Необходимо отфильтровать ОбразовательныеДокументы для СтрокиРекомендательногоСписка. +Необходимо отфильтровать ОбразовательныеДокументы для СтрокиРекомендательногоСписка. При задании `DetailVariableDef` следует указать: `OwnerConnectProp` = ЗаявлениеАбитуриента.Личность, `ConnectMasterProp` = Личность. -Необходимо отфильтровать ОбразовательныеДокументы для СтрокиРекомендательногоСписка. +Необходимо отфильтровать ОбразовательныеДокументы для СтрокиРекомендательногоСписка. При задании `DetailVariableDef` следует указать: `OwnerConnectProp` = ЗаявлениеАбитуриента.Личность, `ConnectMasterProp` = Личность. ### Задание ограничений на псевдодетейлы Например, сущности "Клиент" и "Кредит" связаны представленным на изображении образом. -![](/images/pages/products/flexberry-orm/query-language/pseudo-details.png) +![Пвсевдодетейл](/images/pages/products/flexberry-orm/query-language/pseudo-details.png) Нужно ограничить клиентов, задав при этом ограничение на ссылающихся на них кредиты. - -Очевидно, что с точки зрения хранения данной объектной модели в БД в соответствии с [существующими правилами](fo_storing-data-objects.html), нет различия между агрегацией и простой ассоциацией. Поэтому запросы, ограничивающие выборку по критериям из дочерней таблицы, не отличаются в случае агрегации и ассоциации. Следовательно для построения ограничения в случае всевдодетейла необходимо использовать `DetailVariableDef` совместно с [ExternalLangDef](fo_external-lang-def.html). - + +Очевидно, что с точки зрения хранения данной объектной модели в БД в соответствии с [существующими правилами](fo_storing-data-objects.html), нет различия между агрегацией и простой ассоциацией. Поэтому запросы, ограничивающие выборку по критериям из дочерней таблицы, не отличаются в случае агрегации и ассоциации. Следовательно для построения ограничения в случае всевдодетейла необходимо использовать `DetailVariableDef` совместно с [ExternalLangDef](fo_external-lang-def.html). + Если в описанном примере надо выбрать клиентов, у которых есть кредиты на срок более 15 лет, код будет выглядеть следующим образом: ``` csharp -ExternalLangDef ldef = ExternalLangDef.LanguageDef; +IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. +IDataService ds = mainUnityContainer.Resolve(); +ExternalLangDef languageDef = new ExternalLangDef(ds); LoadingCustomizationStruct lcsДолгосрочныеКлиенты = LoadingCustomizationStruct.GetSimpleStruct(typeof(Клиент), "КлиентE"); lcsДолгосрочныеКлиенты.LoadingTypes = new[) { typeof(Клиент) }; var view = Information.GetView("КредитE", typeof(Кредит)); var dvd = new DetailVariableDef { ConnectMasterPorp = "Клиент", - OwnerConnectProp = new[) { SQLWhereLanguageDef.StormMainObjectKey }, + OwnerConnectProp = new[] { SQLWhereLanguageDef.StormMainObjectKey }, View = view, - Type = ldef.GetObjectType("Details") + Type = languageDef.GetObjectType("Details") }; -lcsДолгосрочныеКлиенты.LimitFunction = ldef.GetFunction(ldef.funcExist, dvd, - ldef.GetFunction(ldef.funcGEQ, - new VariableDef(ldef.GuidType, "СрокКредита"), 15)); -ICSSoft.STORMNET.DataObject[) dobjsДолгосрочныеКлиенты = DataServiceProvider.DataService.LoadObjects(lcsДолгосрочныеКлиенты); +lcsДолгосрочныеКлиенты.LimitFunction = languageDef.GetFunction(languageDef.funcExist, dvd, + languageDef.GetFunction(languageDef.funcGEQ, + new VariableDef(languageDef.GuidType, "СрокКредита"), 15)); +ICSSoft.STORMNET.DataObject[] dobjsДолгосрочныеКлиенты = ds.LoadObjects(lcsДолгосрочныеКлиенты); ``` diff --git a/pages/products/flexberry-orm/views/fo_view-property-appender.ru.md b/pages/products/flexberry-orm/views/fo_view-property-appender.ru.md index d275f49f6..8e5a183c4 100644 --- a/pages/products/flexberry-orm/views/fo_view-property-appender.ru.md +++ b/pages/products/flexberry-orm/views/fo_view-property-appender.ru.md @@ -8,7 +8,7 @@ permalink: ru/fo_view-property-appender.html lang: ru --- -Класс `AdvLimit.ExternalLangDef.ViewPropertyAppender` предназначен для того, чтобы расширять [представление](fd_view-definition.html) свойствами, которые находятся в [ограничении](fo_limit-function.html). +Класс `AdvLimit.ExternalLangDef.ViewPropertyAppender` предназначен для того, чтобы расширять [представление](fd_view-definition.html) свойствами, которые находятся в [ограничении](fo_limit-function.html). ## Основные методы diff --git a/pages/products/flexberry-winforms/controls/groupedit/fw_ge-editor-ext.ru.md b/pages/products/flexberry-winforms/controls/groupedit/fw_ge-editor-ext.ru.md index 2fcdeec46..c7c05e2aa 100644 --- a/pages/products/flexberry-winforms/controls/groupedit/fw_ge-editor-ext.ru.md +++ b/pages/products/flexberry-winforms/controls/groupedit/fw_ge-editor-ext.ru.md @@ -16,7 +16,7 @@ lang: ru 4. При сохранении детейла на форме редактирования не происходит запись в БД - детейл запишется в БД вместе со своим мастером при его сохранении. 5. В случае, когда объект открыт на форме редактирования, запрещено его редактировать в `GroupEdit`(выдаётся предупреждение и выводится на передний план форма редактирования). Для согласованности отображения в `GroupEdit` изменённых на форме данных синхронизируется отображение данных при выходе с формы редактирования и при ее активации. -{% include important.html content="GEEditorExt не входит в стандартную поставку Flexberry Winforms." %} +> GEEditorExt не входит в стандартную поставку Flexberry Winforms. ## Как подключить GEEditorExt @@ -24,7 +24,7 @@ lang: ru ![Пример диаграммы](/images/pages/products/flexberry-winforms/controls/groupedit/class-diagram_-customer-purchase2.jpg) -{% include note.html content="Для редактирования детейлов необходимо сгенерировать соответствующую форму редактирования (при быстрой прототипизации она не создаётся)." %} +> Для редактирования детейлов необходимо сгенерировать соответствующую форму редактирования (при быстрой прототипизации она не создаётся). 1.В классе формы агрегатора объявляется переменную типа `GEEditorExt`: @@ -55,7 +55,7 @@ public class WinformC__ПокупательE : ICSSoft.STORMNET.UI.BaseWinEdit, } ``` -{% include note.html content="Вместо пунктов 1 и 2, если не надо совершать дополнительных действий с кнопками (скрывать их, переименовывать и т.п.) можно использовать метод-расширение у GroupEdit." %} +> Вместо пунктов 1 и 2, если не надо совершать дополнительных действий с кнопками (скрывать их, переименовывать и т.п.) можно использовать метод-расширение у GroupEdit. 3.В метод `GetEditor` формы агрегатора добавляется код, указывающий, какую форму поднимать для редактирования конкретного детейла: @@ -110,7 +110,9 @@ public class C__ПокупкаE : ICSSoft.STORMNET.UI.BaseIndpdEdit if ((dobject.GetStatus(false) != ICSSoft.STORMNET.ObjectStatus.Created) || dobject.Prototyped) { - ICSSoft.STORMNET.Business.DataServiceProvider.DataService.LoadObject(m_objView, dobject, false, false); + IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. + IDataService ds = mainUnityContainer.Resolve(); + ds.LoadObject(m_objView, dobject, false, false); dobject.InitDataCopy(); } // *** Start programmer edit section *** (PrepareDataObjectForEdit (DataObject) end) @@ -132,7 +134,9 @@ ICSSoft.STORMNET.View дочитать_View = m_objView - ge_View; //если она открывалась ранее foreach (string altprop in dobject.GetAlteredPropertyNames()) дочитать_View.RemoveProperty(altprop); -ICSSoft.STORMNET.Business.DataServiceProvider.DataService.LoadObject(дочитать_View, dobject, false, false); +IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. +IDataService ds = mainUnityContainer.Resolve(); +ds.LoadObject(дочитать_View, dobject, false, false); return; ``` diff --git a/pages/products/flexberry-winforms/controls/lookup/fw_lookup-another-object.ru.md b/pages/products/flexberry-winforms/controls/lookup/fw_lookup-another-object.ru.md index c4a2632a3..72b8f18a0 100644 --- a/pages/products/flexberry-winforms/controls/lookup/fw_lookup-another-object.ru.md +++ b/pages/products/flexberry-winforms/controls/lookup/fw_lookup-another-object.ru.md @@ -165,7 +165,9 @@ public override void Edited(ICSSoft.STORMNET.DataObject dataobject, string contp { ДежурнаяГруппаСмены ДежГрСмены = (ДежурнаяГруппаСмены)ДежурныеГруппыСмены.EditManager.DataObject; ДежурнаяГруппа ДежГр = ((ЧленДежурнойГруппы)dataobject).ДежураяГруппа; - ICSSoft.STORMNET.Business.DataServiceProvider.DataService.LoadObject("ДежурнаяГруппаE", ДежГр); + IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. + IDataService ds = mainUnityContainer.Resolve(); + ds.LoadObject("ДежурнаяГруппаE", ДежГр); ДежГрСмены.НомерГруппы = ДежГр.НомерГруппы; ДежГрСмены.ТипДежурнойГруппы = ДежГр.ТипДежурнойГруппы; ДежГрСмены.Руководитель = ДежГр.Руководитель; diff --git a/pages/products/flexberry-winforms/controls/lookup/fw_lookup.ru.md b/pages/products/flexberry-winforms/controls/lookup/fw_lookup.ru.md index 2f68bbf51..693705a85 100644 --- a/pages/products/flexberry-winforms/controls/lookup/fw_lookup.ru.md +++ b/pages/products/flexberry-winforms/controls/lookup/fw_lookup.ru.md @@ -45,7 +45,9 @@ public override void Edited(ICSSoft.STORMNET.DataObject dataobject, string contp Э.ФИОСотрудника = Э.Сотрудник.ОпрПолноеФИО(); if (р.Должность != null) { - DataServiceProvider.DataService.LoadObject(р.Должность); + IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. + IDataService ds = mainUnityContainer.Resolve(); + ds.LoadObject(р.Должность); Э.Должность = р.Должность.Наименование; } else Э.Должность = ""; @@ -86,7 +88,9 @@ public void ПоказатьСписок() LoadingCustomizationStruct lcs = LoadingCustomizationStruct.GetSimpleStruct(typeof(Лицо), "ЛицоL"); lcs.LimitFunction = lf; - ICSSoft.STORMNET.DataObject[] objs = DataServiceProvider.DataService.LoadObjects(lcs); + IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. + IDataService ds = mainUnityContainer.Resolve(); + ICSSoft.STORMNET.DataObject[] objs = ds.LoadObjects(lcs); if (objs.Length == 0) { diff --git a/pages/products/flexberry-winforms/forms/editform/fw_edit-objects-on-forms.ru.md b/pages/products/flexberry-winforms/forms/editform/fw_edit-objects-on-forms.ru.md index d7f559c67..a7ab3ac3c 100644 --- a/pages/products/flexberry-winforms/forms/editform/fw_edit-objects-on-forms.ru.md +++ b/pages/products/flexberry-winforms/forms/editform/fw_edit-objects-on-forms.ru.md @@ -117,7 +117,8 @@ void form1_NextEvent(object sender, EventArgs e) private void GetNextOrPrevObj(bool next) { KeyGuid pk = (KeyGuid)((BaseWinEdit)Editor).DataObject.__PrimaryKey; - IDataService ds = DataServiceProvider.DataService; + IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. + IDataService ds = mainUnityContainer.Resolve(); LoadingCustomizationStruct lcs = LoadingCustomizationStruct.GetSimpleStruct(typeof(Планета), "ПланетаE"); lcs.ColumnsSort = new[] { new ColumnsSortDef("primaryKey", SortOrder.Asc) }; diff --git a/pages/products/flexberry-winforms/forms/editform/fw_editform.ru.md b/pages/products/flexberry-winforms/forms/editform/fw_editform.ru.md index 91c852ee8..1886c0ec5 100644 --- a/pages/products/flexberry-winforms/forms/editform/fw_editform.ru.md +++ b/pages/products/flexberry-winforms/forms/editform/fw_editform.ru.md @@ -254,7 +254,9 @@ private void ContainerCloseHandler (object sender, StormNetUI.CloseEventArgs arg ```csharp Объект oОбъект = new Объект(); oОбъект.__PrimaryKey = 'чего-то там'; -ICSSoft.STORMNET.Business.DataServiceProvider.DataService.LoadObject(oОбъект); +IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. +IDataService ds = mainUnityContainer.Resolve(); +ds.LoadObject(oОбъект); ICSSoft.STORMNET.UI.BaseIndpdEdit cont = (ICSSoft.STORMNET.UI.BaseIndpdEdit)Activator.CreateInstance(typeof(ОбъектE)); ICSSoft.STORMNET.UI.ContRunner.RunEditForm(cont); cont.Edit(oОбъект, "", ""); @@ -265,7 +267,9 @@ cont.Edit(oОбъект, "", ""); ```csharp Объект oОбъект = new Объект(); oОбъект.__PrimaryKey = 'чего-то там'; -ICSSoft.STORMNET.Business.DataServiceProvider.DataService.LoadObject(oОбъект); +IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. +IDataService ds = mainUnityContainer.Resolve(); +ds.LoadObject(oОбъект); ICSSoft.STORMNET.UI.BaseIndpdEdit cont = (ICSSoft.STORMNET.UI.BaseIndpdEdit)Activator.CreateInstance(typeof(ОбъектE)); ICSSoft.STORMNET.UI.ContRunner.RunEditForm(cont); cont.SaveEvent += (sr, ea) => { new BusinessService().UpdateObject(ea.dataobject); }; diff --git a/pages/products/flexberry-winforms/subsystems/limits/fw_advlimit-function-serialization.ru.md b/pages/products/flexberry-winforms/subsystems/limits/fw_advlimit-function-serialization.ru.md index 473ccd8f6..83fa359a9 100644 --- a/pages/products/flexberry-winforms/subsystems/limits/fw_advlimit-function-serialization.ru.md +++ b/pages/products/flexberry-winforms/subsystems/limits/fw_advlimit-function-serialization.ru.md @@ -9,14 +9,15 @@ folder: products/flexberry-winforms/ lang: ru --- -## Средства сериализации-десериализации в `ICSSoft.STORMNET.Windows.Forms.Utils` -В сборке `ICSSoft.STORMNET.Windows.Forms` реализован класс `ICSSoft.STORMNET.Windows.Forms.Utils`, предоставляющий, в частности, методы для сериализации-десериализации, которые применимы в т.ч. для [функции ограничения](fo_limit-function.html). Данные методы представляют собой обертку над соответствующими методами сборки [`ICSSoft.STORMNET.Tools`](fo_ics-soft-stormnet-tools.html), и выполняют обращение к ней. +## Средства сериализации-десериализации в ICSSoft.STORMNET.Windows.Forms.Utils -### Методы сериализации класса `ICSSoft.STORMNET.Windows.Forms.Utils`: +В сборке `ICSSoft.STORMNET.Windows.Forms` реализован класс `ICSSoft.STORMNET.Windows.Forms.Utils`, предоставляющий, в частности, методы для сериализации-десериализации, которые применимы в т.ч. для [функции ограничения](fo_limit-function.html). Данные методы представляют собой обертку над соответствующими методами сборки [`ICSSoft.STORMNET.Tools`](fo_ics-soft-stormnet-tools.html), и выполняют обращение к ней. + +### Методы сериализации класса ICSSoft.STORMNET.Windows.Forms.Utils #### `ObjectToString` - __Назначение__: Сериализация в строку при помощи `SoapFormatter`. + __Назначение__: Сериализация в строку при помощи `SoapFormatter`. __Параметры__: @@ -52,7 +53,8 @@ public static object ObjectFromString(string s) } ``` -#### `ObjectToBinaryString` +#### ObjectToBinaryString + __Назначение__: Сериализация в строку при помощи `BinaryFormatter`. __Параметры__: @@ -70,7 +72,8 @@ public static string ObjectToBinaryString(object o) } ``` -#### `ObjectFromBinaryString` +#### ObjectFromBinaryString + __Назначение__: Десериализация из строки при помощи `BinaryFormatter `(если не получится, то попробуем `SoapFormatter`- для совместимости с унаследованными данными). __Параметры__: @@ -97,12 +100,11 @@ public static object ObjectFromBinaryString(string s) } ``` - На [форме задания ограничений] при сохранении (восстановлении) [LimitFunction](fw_limitation-editform.html) используются методы `Utils.ObjectToBinaryString` (`Utils.ObjectFromBinaryString`), т.е. сериализуются ограничения с помощью бинарной сериализации, а восстанавливаются как бинарные строки, так и SOAP, т.к. в ранних версиях технологии использовалась SOAP-сериализация. ### Пример SOAP-сериализации LimitFunction -```csharp +```csharp Function fn = FunctionBuilder.BuildAnd( FunctionBuilder.BuildEquals("ПарамПамПам", "кто ходит в гости по утрам"), FunctionBuilder.BuildOr( @@ -121,25 +123,29 @@ public static object ObjectFromBinaryString(string s) ``` ### Пример бинарной сериализации LimitFunction + Этот вид сериализации более производительный и строки получаются короче. ```csharp string fnStr = ""; string serializedFn; AdvansedLimit advlimit = new AdvansedLimit(); - ExternalLangDef externalLangDef = ExternalLangDef.LanguageDef; - advlimit.FromSimpleValue(Utils.ObjectFromString(_serializedFunc), externalLangDef); + IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. + IDataService ds = mainUnityContainer.Resolve(); + ExternalLangDef languageDef = new ExternalLangDef(ds); + advlimit.FromSimpleValue(Utils.ObjectFromString(_serializedFunc), languageDef); Function fn = advlimit.Function; - serializedFn = Utils.ObjectToBinaryString(externalLangDef.FunctionToSimpleStruct(fn)); + serializedFn = Utils.ObjectToBinaryString(languageDef.FunctionToSimpleStruct(fn)); Assert.IsNotNull(serializedFn); восставшийИзНебытия = - externalLangDef.FunctionFromSimpleStruct(Utils.ObjectFromBinaryString(serializedFn)); + languageDef.FunctionFromSimpleStruct(Utils.ObjectFromBinaryString(serializedFn)); Assert.IsNotNull(восставшийИзНебытия); ``` ## Возможная проблема десериализации + В коде выше используется конструкция `advlimit.FromSimpleValue`, которая на основании объекта особого вида строит непосредственно [ограничение](fo_limit-function.html). В структуре передаваемого объекта особого вида, среди прочих, есть [`AssemblyQualifiedName`](http://msdn.microsoft.com/ru-ru/library/system.type.assemblyqualifiedname.aspx) типа, из-за чего могут возникнуть проблемы при десериализации: например, если ограничение было создано с неподписанной сборкой, а требуется открыть уже с версией, что была подписана (соответственно, [`AssemblyQualifiedName`](http://msdn.microsoft.com/ru-ru/library/system.type.assemblyqualifiedname.aspx) типа изменилось и его нельзя получить через `Type.GetType(...)`), и др. Для этого случая добавлен делегат, который позволяет определить собственный дополнительный метод для получения типа по его имени. ```csharp @@ -163,6 +169,7 @@ namespace ICSSoft.STORMNET.Windows.Forms ``` Ниже представлен пример использования данного делегата: + ```csharp // ... var obj = ICSSoft.STORMNET.Windows.Forms.Utils.ObjectFromBinaryString(data); @@ -174,7 +181,6 @@ namespace ICSSoft.STORMNET.Windows.Forms var result = advansedLimit; //... -} private Type ExtraTypeResolver(string typeName) { @@ -185,4 +191,4 @@ private Type ExtraTypeResolver(string typeName) return null; } -``` \ No newline at end of file +``` diff --git a/pages/products/flexberry-winforms/subsystems/limits/fw_limit-function-insert-parameters-values.ru.md b/pages/products/flexberry-winforms/subsystems/limits/fw_limit-function-insert-parameters-values.ru.md index 37e96c140..bca903697 100644 --- a/pages/products/flexberry-winforms/subsystems/limits/fw_limit-function-insert-parameters-values.ru.md +++ b/pages/products/flexberry-winforms/subsystems/limits/fw_limit-function-insert-parameters-values.ru.md @@ -10,22 +10,28 @@ lang: ru --- ## Вопрос + Имеется [limitFunction](fo_limit-function.html) (класс `ICSSoft.STORMNET.FunctionalLanguage.Function`) с параметром @Дата. Как вместо этого параметра подставить текущую дату? ## Ответ + Пусть задана функция `limitFunction` с параметром @Дата: -```csharp -ExternalLangDef externalLangDef = ExternalLangDef.LanguageDef; + +```csharp +IUnityContainer mainUnityContainer = ...; // Получение основного контейнера для работы с Unity. +IDataService ds = mainUnityContainer.Resolve(); +ExternalLangDef languageDef = new ExternalLangDef(ds) - ICSSoft.STORMNET.FunctionalLanguage.Function limitFunction = externalLangDef.GetFunction( - externalLangDef.funcEQ, - new ParameterDef("Дата", externalLangDef.DateTimeType, false, ""), + ICSSoft.STORMNET.FunctionalLanguage.Function limitFunction = languageDef.GetFunction( + languageDef.funcEQ, + new ParameterDef("Дата", languageDef.DateTimeType, false, ""), new DateTime(2000, 01, 01)); ``` Подробнее о [ExternalLangDef](fo_external-lang-def.html). ### Для Web + Для подстановки параметров в функцию в классе `ICSSoft.STORMNET.Web.Tools.AdvLimitUtils` есть метод: ```csharp @@ -47,6 +53,7 @@ public static Function SubstituteParameters(Function function, IDictionary @@ -63,6 +70,7 @@ public static Function SubstituteParameters(Function function, IDictionary