[ELMA3] Архитектура объектной модели
Общие принципы
Объектная модель системы – набор классов, сущностей, перечислений, которые используются в предметной области. Под сущностью в системе ELMA будем понимать объект, способный храниться в базе данных. Основные классы для работы с объектной моделью представлены в сборке EleWise.ELMA.SDK в пространствах имен, начинающихся с EleWise.ELMA.Model.
Работа с объектной моделью системы ELMA построена на следующих принципах:
Метаданные
Описание объектной модели в системе ELMA основано на использовании метаданных.
Метаданные – данные, описывающие некоторый элемент объектной модели (например, тип сущности, перечисление и т.д.).
Для создания метаданных (создания типов сущностей, перечислений) используется специальный плагин к Visual Studio, позволяющий визуально описывать модель системы (см. статью Редактор сущностей). Основные типы метаданных представлены в пространстве имен EleWise.ELMA.Model.Metadata. В файловой системе метаданные хранятся в файлах формата .md (в действительности - обычный xml-файл).
Пример метаданных сущности:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | <?xml version= "1.0" encoding= "utf-8" ?> <Entity xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd= "http://www.w3.org/2001/XMLSchema" IsUnique= "true" > <Uid>04d5bcbf-4288-4d95-9745-1ebd0d690bb3</Uid> <Name>User</Name> <DisplayName>Пользователь</DisplayName> <Namespace>EleWise.ELMA.Model.Entities.Security</Namespace> <Properties> <PropertyMetadata xsi:type= "EntityPropertyMetadata" > <Uid>9357aacc-d37f-497a-99f4-4a106765f8e1</Uid> <Name>UserName</Name> <DisplayName>Учетная запись</DisplayName> <TypeUid>9b9aac17-22bb-425c-aa93-9c02c5146965</TypeUid> <Settings xsi:type= "StringSettings" > <FieldName>UserName</FieldName> </Settings> <Required> true </Required> <Filterable> true </Filterable> </PropertyMetadata> <PropertyMetadata xsi:type= "EntityPropertyMetadata" > <Uid>a1e9ab10-6dad-4a11-a190-8f9d11b9ed77</Uid> <Name>Password</Name> <DisplayName>Пароль</DisplayName> <TypeUid>9b9aac17-22bb-425c-aa93-9c02c5146965</TypeUid> <Settings xsi:type= "StringSettings" > <FieldName>Password</FieldName> </Settings> </PropertyMetadata> </Properties> <Type>Interface</Type> <ImplementationUid>18faf3ae-03c9-4e64-b02a-95dd63e54c4d</ImplementationUid> <TableName>User</TableName> <Filterable> true </Filterable> </Entity> |
На основе метаданных автоматически генерируется исходный код на C# с типами, которые определяют метаданные. В данном случае будет автоматически сгенерирован следующий код:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | namespace EleWise.ELMA.Model.Entities.Security { /// <summary> /// Пользователь /// </summary> [MetadataType( typeof (EntityMetadata))] [EntityMetadataType(EntityMetadataType.Interface)] [Uid( "04d5bcbf-4288-4d95-9745-1ebd0d690bb3" )] [ImplementationUid( "18faf3ae-03c9-4e64-b02a-95dd63e54c4d" )] public partial interface IUser : IEntity< long > { /// <summary> /// Учетная запись /// </summary> string UserName { get ; set ; } /// <summary> /// Пароль /// </summary> string Password { get ; set ; } } } |
NHibernate
Для работы с базой данных в ELMA используется ORM-компонент NHibernate.Для упрощения работы с NHibernate в SDK ELMA реализован следующий функционал:
- маппинги сущностей создаются автоматически при создании через расширение для Visual Studio;
- работа с сессиями ведется в менеджерах сущностей;
- для менеджеров сущностей существует базовый класс, реализующий основные методы для работы с ними (Load, Save, Find и т.д.);
- транзакционность обеспечивается навешиванием атрибута TransactionAttribute на методы менеджера.
Менеджеры
Менеджер – некий сервис, предназначенный для работы с одним или несколькими элементами объектной модели. Обычно менеджеры создаются для работы с сущностями (см. статью Менеджеры сущностей).
Расширяемость объектной модели
Расширяемость объектной модели – принцип, позволяющий модулям системы создавать свои модели, а также расширять существующие (например, добавлять свойства в сущности из другого модуля. Данный принцип основан на использовании интерфейсов сущностей и интерфейсов расширения сущностей (см. статью Сущности).
Модули с объектными моделями
Элементы объектной модели (сущности, перечисления) можно создавать в любой сборке при наличии у нее атрибута EleWise.ELMA.Model.Attributes.ModelAssemblyAttribute.
Добавить его можно двумя способами:
1. Вручную – прописав в Properties\AssemblyInfo.cs следующую строчку:
1 | [assembly: EleWise.ELMA.Model.Attributes.ModelAssemblyAttribute] |
2. Используя расширение для Visual Studio, добавив элемент с типом ELMA Assembly Info и поставив галочку Сборка содержит модели.
Сущности
См. статью Сущности.
Работа с метаданными
Для работы с метаданными существует служба EleWise.ELMA.Model.Services.IMetadataRuntimeService.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | namespace EleWise.ELMA.Model.Services { /// <summary> /// Интерфейс сервиса для получения информации о метаданных /// </summary> [ExtensionPoint] public interface IMetadataRuntimeService { /// <summary> /// Получить тип по уникальному идентификатору /// </summary> /// <param name="uid">Уникальный идентификатор типа</param> /// <param name="loadImplementation">Загружать ли метаданные реализации, если указанный тип - интерфейс</param> /// <returns>Тип</returns> Type GetTypeByUid(Guid uid, bool loadImplementation = true ); /// <summary> /// Получить метаданные по уникальному идентификатору /// </summary> /// <param name="uid">Уникальный идентификатор метаданных</param> /// <param name="loadImplementation">Загружать ли метаданные реализации, если указанный тип - интерфейс</param> /// <returns>Метаданные</returns> IMetadata GetMetadataByUid(Guid uid, bool loadImplementation = true ); /// <summary> /// Зарегистрировать тип /// </summary> /// <param name="type">Тип</param> void RegisterType(Type type); /// <summary> /// Получить список метаданных /// </summary> /// <returns>Список метаданных</returns> IEnumerable<IMetadata> GetMetadataList(); /// <summary> /// Получить описание типа данных по его уникальному идентификатору. Если не нашли - null /// </summary> /// <param name="typeUid">Уникальный идентификатор типа данных</param> /// <returns>Описание типа данных</returns> ITypeDescriptor GetTypeDescriptor(Guid typeUid); /// <summary> /// Получить описание типа данных по его типу CLR. Если не нашли - null /// </summary> /// <param name="runtimeType">Тип CLR</param> /// <returns>Описание типа данных</returns> ITypeDescriptor GetTypeDescriptor(Type runtimeType); /// <summary> /// Получить описание типа данных, который можно использовать для первичного ключа, по его уникальному идентфикатору. Если не нашли - null /// </summary> /// <param name="typeUid">Уникальный идентификатор типа данных</param> /// <returns>Описание типа данных</returns> ITypeDescriptor GetIdTypeDescriptor(Guid typeUid); } } |