Архитектура объектной модели

Общие принципы

Объектная модель системы - набор классов, сущностей, перечислений, которые используются в предметной области. Под сущностью в системе ELMA будем понимать объект, способный храниться в базе данных. Основные классы для работы с объектной моделью представлены в сборке EleWise.ELMA.SDK в пространствах имен, начинающихся с EleWise.ELMA.Model.

Работа с объектной моделью системы ELMA построена на следующих принципах:

Метаданные

Описание объектной модели в системе ELMA основано на использовании метаданных.

Метаданные - данные, описывающие некоторый элемент объектной модели (например, тип сущности, перечисление и т.д.).

Для создания метаданных (создания типов сущностей, перечислений) используется специальный плагин к Visual Studio, позволяющий визуально описывать модель системы (см. статью Редактор сущностей). Основные типы метаданных представлены в пространстве имен EleWise.ELMA.Model.Metadata. В файловой системе метаданные хранятся в файлах формата ".md" (в действительности - обычный xml-файл).

Пример метаданных сущности:

<?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# с типами, которые определяют метаданные. В данном случае будет автоматически сгенерирован следующий код:

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 следующую строчку

[assembly: EleWise.ELMA.Model.Attributes.ModelAssemblyAttribute]

2. Используя расширение для Visual Studio, добавив элемент с типом ELMA Assembly Info и поставив галочку Сборка содержит модели.

Сущности

См. статью Сущности.

Работа с метаданными

Для работы с метаданными существует служба EleWise.ELMA.Model.Services.IMetadataRuntimeService.

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);

    }

}

Ссылки на элементы API

IMetadataRuntimeService