Разработка преобразователя данных
Неотъемлемой частью разработки объектной модели карточки является разработка преобразователя данных — объект, в котором объясняется каким образом элементы объектной модели карточки (или секций) связаны с данными этой карточки в базе данных.
Контекст объектов задействует преобразователь данных на этапе создания экземпляра карточки (к примеру, методом GetObject
), а также при сохранении новых или изменённых данных.
Преобразователь данных разрабатывается для каждого созданного класса строки секции, а также для самой карточки.
С программной точки зрения, преобразователь данных должен вернуть объект типа ObjectMap
(карта преобразователя), который содержит списки, связывающие элементы объектной модели с их эквивалентами в схеме метаданных карточки.
Далее рассматривается пример разработки преобразователей для строк секций и карточки, рассмотренных ранее.
Преобразователь данных для строки секции
Базовым классом преобразователя для строки (не зависит от типа секции) является класс CardRowMapper
. Для класса CardRowMapper
указывается тип, соответствующий классу объектной модели строки для которой он создаётся.
internal sealed class SampleCardStructSectionMapper : CardRowMapper<SampleCardStructSection>
{
private static ObjectMap map;
static SampleCardStructSectionMapper() (1)
{
SampleCardStructSectionMapper.InitializeObjectMap(); (2)
}
public SampleCardStructSectionMapper(ObjectContext context) : base(context) (3)
{
}
protected override ObjectMap GetObjectMap() (4)
{
return SampleCardStructSectionMapper.map;
}
protected override SampleCardStructSection CreateObject(ObjectInitializationData data) (5)
{
return new SampleCardStructSection(data);
}
private static void InitializeObjectMap() (6)
{
SampleCardStructSectionMapper.map = new ObjectMap();
SampleCardStructSectionMapper.map.ObjectTypeId = new Guid("78006F34-55DF-497F-BD62-E0A33C8EEABF"); (7)
SampleCardStructSectionMapper.map.Field(SampleCardStructSection.NameProperty, "Name"); (8)
SampleCardStructSectionMapper.map.Reference(SampleCardStructSection.AuthorProperty, "Author"); (9)
}
}
1 | Обязательный статический конструктор. |
2 | Создаем карту преобразователя. |
3 | Обязательный конструктор для передачи текущего контекста объектов. |
4 | Обязательный метод, предоставляющей карту. |
5 | Создание экземпляра объекта секции с заранее подготовленными данными. |
6 | Создание карты преобразователя. |
7 | Указываем идентификатор секции в схеме карточки. |
8 | Связываем обычное поле.
Первый аргумент объявление поля в классе секции, а второй аргумент — название поля в схеме карточки. |
9 | Связываем ссылочное поле. |
Преобразовать для строки коллекционной секции не отличается от преобразователя для строки плоской секции.
public class SampleCardTreeSectionMapper : CardRowMapper<SampleCardTreeSection>
{
private static ObjectMap map;
static SampleCardTreeSectionMapper()
{
SampleCardTreeSectionMapper.InitializeObjectMap();
}
public SampleCardTreeSectionMapper(ObjectContext context) : base(context)
{
}
protected override ObjectMap GetObjectMap()
{
return SampleCardTreeSectionMapper.map;
}
protected override SampleCardTreeSection CreateObject(ObjectInitializationData data)
{
return new SampleCardTreeSection(data);
}
private static void InitializeObjectMap()
{
SampleCardTreeSectionMapper.map = new ObjectMap();
SampleCardTreeSectionMapper.map.ObjectTypeId = new Guid("08ACDC17-EAB7-4E66-8C6D-428F09490F3A");
SampleCardTreeSectionMapper.map.Collection(SampleCardTreeSection.DescendantsProperty, new Guid("80DB0D9B-D1E8-4A4D-8001-E71AC07B10CE")); (1)
}
}
1 | В карту добавляется подчиненная секция. Первым аргументом передается объявление секции в родительской секции, а вторым — её идентификатор из схемы метаданных. |
Преобразователь данных для карточки
Преобразователь данных для карточки оформляется аналогичным образом, за исключением базового класса (должен быть класс BaseCardMapper<T>
) и того, что в карте присутствуют исключительно секции.
public class SampleCardMapper : CardMapper<SampleCard>
{
private static ObjectMap map;
static SampleCardMapper()
{
SampleCardMapper.InitializeObjectMap();
}
public SampleCardMapper(ObjectContext context) : base(context)
{
}
protected override ObjectMap GetObjectMap()
{
return SampleCardMapper.map;
}
protected override SampleCard CreateObject(ObjectInitializationData data)
{
return new SampleCard(data);
}
private static void InitializeObjectMap()
{
SampleCardMapper.map = new ObjectMap();
SampleCardMapper.map.ObjectTypeId = new Guid("E1BF5846-FE0C-424B-9B71-B58D1A526BCF"); (1)
SampleCardMapper.map.Collection(SampleCard.StructSectionProperty, new Guid("A3F0B456-587E-4769-B019-467AD4EB9BF8")); (2)
SampleCardMapper.map.Collection(SampleCard.CollectionSectionProperty, new Guid("F6E9E009-7447-435D-8DB8-C3E4187E2D61"));
SampleCardMapper.map.Collection(SampleCard.TreeSectionProperty, new Guid("EA968311-3702-4568-9663-2CE9CBE09CC6"));
}
}
1 | Идентификатор типа карточки. |
2 | Регистрация секций в карте преобразователя. |
Преобразователь данных для справочника
Класс преобразователя данных для справочника реализуется по аналогии с преобразователя данных карточки. Единственное отличие — базовый класс здесь DictionaryMapper<T>
.
public class SampleDictionaryMapper : DictionaryMapper<SampleDictionary>
{
private static ObjectMap map;
static SampleDictionaryMapper()
{
SampleDictionaryMapper.InitializeObjectMap();
}
public SampleDictionaryMapper(ObjectContext context) : base(context)
{
}
protected override ObjectMap GetObjectMap()
{
return SampleDictionaryMapper.map;
}
protected override SampleDictionary CreateObject(ObjectInitializationData data)
{
return new SampleDictionary(data);
}
private static void InitializeObjectMap()
{
SampleDictionaryMapper.map = new ObjectMap();
SampleDictionaryMapper.map.ObjectTypeId = new Guid("4E32BC51-5F50-4F68-9D0F-3BFBB6523B14"); (1)
SampleDictionaryMapper.map.Collection(SampleDictionary.TreeSectionProperty, new Guid("0CD96A19-59EF-44EC-AF47-977A56BDDB32"));
}
}
1 | Идентификатор типа справочника. |
Регистрация преобразователей данных
Когда классы преобразователей данных били разработаны, требуется создать ещё один класс — фабрика преобразователей данных. В созданном классе нужно связать тип преобразователя к классу карточки или секции, за который он отвечает. Базовым классом для фабрики преобразователей данных выступает класс ObjectMapperFactory
.
public sealed class SampleCardsMapperFactory : ObjectMapperFactory
{
public SampleCardsMapperFactory(ObjectContext context) : base(context)
{
base.RegisterObjectMapper(typeof(SampleCardStructSection), typeof(SampleCardStructSectionMapper)); (1)
base.RegisterObjectMapper(typeof(SampleCardCollectionSection), typeof(SampleCardCollectionSectionMapper));
base.RegisterObjectMapper(typeof(SampleCardTreeSection), typeof(SampleCardTreeSectionMapper));
base.RegisterObjectMapper(typeof(SampleCard), typeof(SampleCardMapper));
}
}
1 | В метод передается тип объектной модели строки секции или карточки, а также тип соответствующего преобразователя. |
Чтобы контекст объектов мог работать с типами карточек и секций, для которых разработаны фабрики преобразователей данных, эти фабрики должны быть добавлены в контекст (см. на примере добавления фабрики BackOfficeMapperFactory
в примере).