Использование EntityMapper
Glossary Item Box
Общие сведения
Класс Terrasoft.Configuration.EntityMapper — это утилитный класс конфигурации, который реализован в схеме EntittyMapper пакета [FinAppLending] продукта Lending. EntittyMapper позволяет сопоставлять данные одной сущности (Entity) с другой сущностью по правилам, определенным в конфигурационном файле. Использование подхода сопоставления данных разных сущностей позволяет избежать появления однообразного кода.
В продукте Lending существует два объекта, содержащих одинаковые колонки. Это объекты [Физ. лицо] ([Contact]) и [Анкета] ([AppForm]). Также существует несколько деталей, относящихся к объекту [Физ. лицо] ([Contact]) и имеющих похожие детали, относящиеся к [Анкета] ([AppForm]). Очевидно, что при заполнении анкеты должна быть возможность по колонке [Id] объекта [Физ. лицо] ([Contact]) получить список всех его колонок и значений, а также список нужных деталей с их колонками и значениями, и сопоставить эти данные с данными, связанными с анкетой. После этого можно автоматически заполнить поля анкеты сопоставленными данными. Таким образом можно существенно уменьшить затраты на ручной ввод одинаковых данных.
Описание кейса
Для проверки механизма сопоставления данных с помощью Terrasoft.Configuration.EntityMapper необходимо создать пользовательский класс UsrEntityMapperConfigsContainer. В этом классе нужно реализовать логику настройки сопоставления данных объектов [Физ. лицо] ([Contact]) и [Анкета] ([AppForm]). Чтобы вызывать выполнение сопоставления со стороны клиентской части приложения, нужно реализовать пользовательский конфигурационный сервис. В профиль страницы редактирования необходимо анкеты добавить кнопку, которая будет вызывать пользовательский конфигурационный сервис и выводить результат в консоль браузера.
Алгоритм реализации кейса
1. Создать пользовательский класс сопоставления данных UsrEntityMapperConfigsContainer
Создание схемы [Исходный код]подробно описано в статье "Создание схемы [Исходный код]".
Для созданной схемы необходимо установить следующие значения свойств:
- [Заголовок] ([Title]) — "UsrEntityMapperConfigsContainer".
- [Название] ([Name]) — "UsrEntityMapperConfigsContainer".
- [Пакет] ([Package]) — "Custom" (или другой пользовательский пакет).
На вкладку [Исходный код] схемы необходимо добавить следующий код:
namespace Terrasoft.Configuration { using System; using System.Collections.Generic; // Класс содержит настройки сопоставления. public class UsrEntityMapperConfigsContainer { // Настройки сопоставления контакта и анкеты. public MapConfig ContactToAppFormConfig { get; protected set; } public UsrEntityMapperConfigsContainer() { this.InitContactToAppFormConfig(); } // Выполняет настройку сопоставления контакта и анкеты. protected virtual void InitContactToAppFormConfig() { var columns = new Dictionary<string, string>(); // В данном случае названия колонок контакта и анкеты совпали. columns.Add("Surname", "Surname"); columns.Add("GivenName", "GivenName"); columns.Add("MiddleName", "MiddleName"); columns.Add("INN", "INN"); columns.Add("SpouseSurname", "SpouseSurname"); columns.Add("SpouseGivenName", "SpouseGivenName"); columns.Add("SpouseMiddleName", "SpouseMiddleName"); columns.Add("Spouse", "Spouse"); var config = new MapConfig { SourceEntityName = "Contact", Columns = columns, RelationEntities = new List<RelationEntityMapConfig>() { new RelationEntityMapConfig() { SourceEntityName = "Contact", ParentColumnName = "Spouse", Columns = new Dictionary<string, string>() { { "Surname", "SpouseSurname" }, { "BirthDate", "SpouseBirthDate" } } } }, DetailsConfig = new List<DetailMapConfig>() { new DetailMapConfig() { SourceEntityName = "ContactAddress", DetailName = "RegistrationAddressFieldsDetail", Columns = new Dictionary<string, string>() { { "AddressType", "AddressType" }, { "Country", "Country" }, { "Region", "Region" } }, Filters = new List<EntityFilterMap>() { new EntityFilterMap(){ ColumnName = "AddressType", Value = BaseFinanceConst.RegistrationAddressTypeId } } } }, CleanDetails = new List<string>() { "AppFormIncomeDetail" } }; this.ContactToAppFormConfig = config; } } }
После внесения изменений схему необходимо опубликовать.
2. Создать пользовательский конфигурационный сервис сопоставления данных
Создание пользовательского конфигурационного сервиса подробно описано в статье "Создание пользовательского конфигурационного сервиса".
Для этого необходимо в пользовательском пакете создать схему [Исходный код] ([Source Code]). Для созданной схемы необходимо установить следующие значения свойств:
- [Заголовок] ([Title]) — "UsrEntityMappingService".
- [Название] ([Name]) — "UsrEntityMappingService".
- [Пакет] ([Package]) — "Custom" (или другой пользовательский пакет).
На вкладку [Исходный код] схемы необходимо добавить следующий код:
namespace Terrasoft.Configuration { using System; using System.Linq; using System.Collections.Generic; using System.Runtime.Serialization; using System.ServiceModel; using System.ServiceModel.Activation; using System.ServiceModel.Web; using Terrasoft.Core; using Terrasoft.Core.Factories; using Terrasoft.Core.Entities; using Terrasoft.Common; using System.Web; using Terrasoft.Web.Common; using Terrasoft.Nui.ServiceModel.DataContract; using Terrasoft.Common.Json; using Terrasoft.Core.Configuration; /// Класс сервиса сопоставления сущностей и их деталей. [ServiceContract] [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)] public class UsrEntityMappingService: BaseService { private EntityMapper _entityMapper; // Возвращает экземпляр EntityMapper. protected virtual EntityMapper EntityMapper { get { return _entityMapper ?? (_entityMapper = ClassFactory.Get<EntityMapper>( new ConstructorArgument("userConnection", this.UserConnection))); } } // Возвращает настройки сопоставления. protected virtual MapConfig GetConfig() { UsrEntityMapperConfigsContainer mapperConfigsContainer = new UsrEntityMapperConfigsContainer(); return mapperConfigsContainer.ContactToAppFormConfig; } // Выполняет сопоставление и возвращает результат. Основной метод сервиса. [OperationContract] [return: MessageParameter(Name = "result")] [WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.Wrapped, RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)] public EntityMappingResult GetMappedEntity(string id) { EntityMappingResult result = new EntityMappingResult(); try { Guid recordId; MapConfig config = this.GetConfig(); EntityResult entityResult = new EntityResult(config); result.columns = entityResult.Columns; result.details = entityResult.Details; if (!Guid.TryParse(id, out recordId)) { return result; } entityResult = EntityMapper.GetMappedEntity(recordId, config); result.columns = entityResult.Columns; result.details = entityResult.Details; result.Success = true; } catch (Exception e){ result.Success = false; result.Exception = e; } return result; } } }
После внесения изменений схему необходимо опубликовать.
3. Добавить кнопку вызова сервиса на странице редактирования заявки
Для этого необходимо заместить существующую схему [Страница редактирования анкеты по заявке] ([Application Form Edit Page]). Замещение клиентских схем подробно описано в статье "Создание клиентской схемы".
В замещающей схеме нужно добавить локализуемую строку (рис. 1) со следующими свойствами:
- [Заголовок] ([Title]) — "Вызвать сервис" ("Call service").
- [Название] ([Name]) — "EntityMappingButtonCaption".
Рис. 1. — Добавление локализуемой строки
На вкладку [Исходный код] схемы необходимо добавить следующий код:
define("AppFormPage", [], function() { return { entitySchemaName: "AppForm", methods: { // Функция запроса к пользовательскому сервису. requestContactData2: function() { var data = { id: this.get("Contact").value }; // Конфигурационный объект для передачи параметров сервису. var config = { serviceName: "UsrEntityMappingService", methodName: "GetMappedEntity", data: data }; // Вызов сервиса. this.callService(config, this.parseMappedEntityResponse2, this); }, //Callback-функция для вывода ответа от сервиса в консоль. parseMappedEntityResponse2: function(response) { window.console.log("Ответ от UsrEntityMappingService", response); } }, diff: /**SCHEMA_DIFF*/[ { "operation": "insert", "parentName": "ProfileContainer", "propertyName": "items", "name": "EntityMappingButton", "values": { itemType: Terrasoft.ViewItemType.BUTTON, "style": Terrasoft.controls.ButtonEnums.style.GREEN, // Привязка заголовка кнопки к локализуемой строке схемы. caption: { bindTo: "Resources.Strings.EntityMappingButtonCaption" }, // Привязка метода-обработчика нажатия кнопки. click: { bindTo: "requestContactData2" }, "layout": { "column": 0, "row": 2, "colSpan": 24 } } } ]/**SCHEMA_DIFF*/ }; });
Здесь в массив diff добавляется конфигурационный объект, с помощью которого в профиль страницы редактирования заявки добавляется кнопка. При нажатии на кнопку вызывается метод requestContactData2(), в котором выполняется вызов пользовательского конфигурационного сервиса UsrEntityMappingService с необходимыми параметрами. После получения ответа от сервиса выполняется вызов сallback-функции parseMappedEntityResponse2(), которая и выводит в консоль браузера ответ от сервиса.
Вместо вывода в консоль браузера можно реализовать автозаполнение полей страницы редактирования анкеты сопоставленными значениями. Однако, эта функциональность уже добалена в методах requestContactData() и parseMappedEntityResponse() родительской схемы AppFormPage.
После внесения изменений схему необходимо сохранить.
В результате выполнения кейса на странице редактирования анкеты появится кнопка, после нажатия на которую в консоли браузера будет выведен объект с сопоставленными данными (рис. 2).
Рис. 2. — Результат выполнения кейса
Если страница редактирования анкеты открыта в режиме новой записи, то необходимо предварительно выбрать или создать контакт, связанный с создаваемой анкетой. Если контакт не будет выбран, возникнет исключение, т.к. this.get("Contact") вернет null.