"Mapping" - новый инструмент LPgenerator! Технология проведения миграции данных в крупных проектах

Десятки слов ежегодно приходят в русский язык, поселяются в нём и режут нам слух. Англицизмы используются не к месту и невпопад, термины теряют своё первоначальное значение и переселяются в новые области, а давно знакомые слова вдруг появляются в незнакомом контексте — запутаться проще простого. Журнал «Стрелка» наводит порядок в рубрике «Словарный запас».

Откуда пришло

Слово образовано от английского «map» и присоединённого к нему суффикса -ing. Дословный перевод — нанесение на карту, картографирование и топографическая съёмка. В последнее время «мэппинг» используется в более широком значении, выходя за рамки исключительно топографической тематики.

Что написано в словаре

«Мэппинг — графическое представление процедуры, процесса, структуры или системы, которое отражает расположение или отношения компонентов, а также документирует потоки, например денежные, энергетические, товарные, информационные, миграционные». (businessdictionary.com)

«Видеомэппинг — также используется значение 3D-мэппинг — направление в аудиовизуальном искусстве, представляющее собой 3D-проекцию на физический объект окружающей среды с учётом его геометрии и местоположения в пространстве». (projection-mapping.org)

В значении «визуализация» — «метод представления информации в виде оптического изображения (например, в виде рисунков и фотографий, графиков, диаграмм, структурных схем, таблиц, карт и т. д.). Очень эффективно используется для представления изначально не зрительной информации (например, температуры, плотности населения, распределения уровней электромагнитных полей и т. д.)» (Словарь бизнес-терминов. «Академик.ру». 2001)

«Майндмэппинг — графическая техника, в основе которой лежит использование природной склонности мозга мыслить ассоциативно, от центра к периферии». (mind-mapping.co.uk)

Что говорят эксперты

Куба Снопек, преподаватель института «Стрелка», — о мэппинге как инструменте изучения города

«Я не называю мэппинг картографией потому, что картография — это признанная научная дисциплина, и она подразумевает очень чёткий метод. Если кратко: человек идёт в новое место и наносит всё, что видит.

Мэппинг, который мы используем как инструмент изучения города на „Стрелке“, отличается и подразумевает отражение процессов, происходящих в городе. Мы создаём карту поверх существующей и проверяем, что изменилось с момента создания геодезической основы. И у каждого исследователя может получиться своя карта одного и того же пространства. Это самая интересная часть: один может смотреть только на архитектуру, другой — на поведение людей, третий — на поведение животных или на световую гамму.

У меня любой проект начинается с карты. Без этого невозможно двигаться дальше. Сейчас я делаю проект, связанный с польскими церквями. Там карта из четырёх тысяч объектов, и анализ этой карты — самая главная часть проекта, она основной его документ».

Алексей Розов, сооснователь компании «Сила света», — о 3D-мэппинге

«Смысл 3D-мэппинга заключается в том, что мы создаём картинку, которая накладывается на физический объект в соответствии с его формами и архитектурой. Именно это даёт возможность видоизменять здание с помощью 3D-трансформации или изменения текстур.

Сначала инженеры делают 3D-модель здания. Если конструкция не очень сложная, то модель можно сделать, съездив на территорию и сняв размеры. Если это, например, Большой театр, в таком случае делается лазерное сканирование, и модель создают по получившемуся в результате облаку точек.

Наземное лазерное 3D сканирование фасадов / фото: severnpartnership.com

Затем аниматоры-художники в программах 3D-моделирования создают контент. Пока они рисуют, инженеры делают расчёты того, сколько нужно проекторов и какой мощности, чтобы покрыть поверхность здания. Например, на Большой театр нужно 12 проекторов, на Манеж — восемь, на МГУ — 86. Также делаются расчёты по яркости и разрешению картинки. Затем виртуальный set-up — настройка всех проекторов, чтобы они составляли единую картину. Когда контент готов, все выезжают непосредственно на площадку. На месте собирается башня для проекторов, устанавливаются необходимые сервера, и инженеры начинают сводить изображение, чтобы оно ровно попадало на здание. Включается компьютер с загруженным контентом, и шоу начинается. Ошибок быть не должно. Если только совсем мелкие, незаметные обычному зрителю. Я видел неудачные примеры того, когда люди хотели сделать 3D-мэппинг, но у них получилась некрасивая графика, не очень точно проекция попадала на объект, неправильно рассчитан свет, исходящий из проектора, — и получается, что всё выглядит тускло, изображение пиксельное, и это не украшает, а, наоборот, только портит.

Время, потраченное на один проект, зависит от масштаба здания и протяжённости ролика. Если вы, например, делаете шоу для МГУ на полчаса, то вам, по-хорошему, нужен год на его создание, а если для Большого театра продолжительностью три минуты, вам достаточно месяца-двух.

Трудно сказать, насколько это развито в России по сравнению с другими странами, но, например, в Москве проходит мощный ежегодный фестиваль „Круг света“. Сегодня появилась тенденция использовать 3D-мэппинг как интерьерный дизайн: на постоянной основе в музее или торговом центре несколько раз в день включают шоу для гостей».

Примеры употребления

«Мэппинг раскрывает экономическую, культурную и политическую ценность информации, которую даёт пространство. Метод позволяет объединить всю эту информацию и привязать её к конкретному месту». (Strelka Magazine)

«К 125-летию чешская Академия наук подготовила визуальное шоу — видеомэппинг на своём историческом здании в Праге». (420on.cz)

«На русский язык майндмэппинг переводится как „карта мышления“, „карта ума“, „карта памяти“, „ментальные карты“. Метод визуализации можно применять для создания новых идей, анализа и упорядочивания информации, конспектирования, принятия решений и много другого». («Наука и жизнь»)

Замеппленые классы должны декларировать столбец первичного ключа в таблице базы данных. Большинство классов также должны описывать собственные свойства в стиле JavaBeans, включая уникальный идентификатор сущности. Элемент в mapping-файле определят отображение этого уникального поля на столбец таблицы, выступающий в роли основного ключа (primary key).

(5)

(1)

name (необязательный): Наименование свойства идентификатора.

(2)

type (необязательный): Имя определяющее Hibernate-тип свойства.

(3)

column (необязательно - по умолчанию имя свойства): Название колонки основного ключа.

(4)

unsaved-value (необязательно - по умолчанию null): Значени свойства идентификатора, которое обзначает, что экземпляр новый (в терминах персистентного хранилища). Отличает данный экземпляр от транзитных экземпляров, которые были загружены или сохранены в предыдущей версии.

(5)

access (необязательный - по умолчанию property): Эту стратегию Hibernate будет использовать для доступа к данному свойству объекта.

Если атрибут name не указан, предполагается, что класс не имеет свойства идентификатора.

Атрибут unsaved-value важен! Если свойство идентификатор вашего класса по умолчанию не null, вы должны установить атрибут "unsaved-value" в соответствующее значение.

Существует альтернативное объявление для доступа к унаследованным (legacy) данным c композитными ключами. Мы настойчиво не рекомендуем использовать композитные ключи в других случаях.

5.1.4.1. generator

Обязательный дочерний элемент "а определяет Java класс используемый для генерации уникальных идентификаторов экземпляров песистентных классов. При необходимости используется элемент Для передачи параметров инициализации или конфигурирации экземпляра генератора.

uid_table next_hi_value_column

Все генераторы реализуют интерфейс net.sf.hibernate.id.IdentifierGenerator. Это очень простой интерфейс; многие приложения могут использовать свою специальную реализацию генератора. Несмотря на это, Hibernate включает в себя множество встроенных генераторов. Ниже идут краткие наименования (ярлыки) для встроенных генераторов:

Increment

генерирует идентификаторы типа long, short или int, уникальные только когда другие процессы не добавляют данные в ту же таблицу. Не использовать в кластере.

identity

Поддерживает identity колонки в in DB2, MySQL, MS SQL Server, Sybase и HypersonicSQL. Тип возвращаемого идентификатора long, short или int.

sequence

Использует последовательность (sequence) в DB2, PostgreSQL, Oracle, SAP DB, McKoi или generator в Interbase. Тип возвращаемого идентификатора long, short или int.

hilo

Использует hi/lo алгоритм для эффективной генерации идентификаторов которые имеют тип long, short или int, требуют наименования таблицы и столбца (по умолчанию hibernate_unique_key и next_hi соответсвенно), как источник значений hi. Алгоритм hi/lo генерирует идентификаторы которые кникальный только для отдельный баз данных. Не используйте этот генератор для соединений через JTA или пользовательских соединений.

seqhilo

использует алгоритм hi/lo для генерации идентификаторов типа long, short или int, с использованием последовательности (sequence) базы данных.

uuid.hex

Использует 128-битный UUID алгоритм для генерации строковых идентификаторов, уникальных в пределах сети (изспользуется IP-адрес). UUID - строка длинной в 32 символа, содержащая шеснадцатеричное представление числа.

uuid.string

использует тот же UUID алгоритм, однако строка при использовании этого генератора состоит из 16 (каких-то) ANSII символов. Не использовать с PostgreSQL.

native

выбирает identity, sequence или hilo, в зависимости от возможностей используемой базы данных.

assigned

предоставляет приложению возможность самостоятельно задать идентификатор объекта перед вызовом метода save().

foreign

используется идентификатор другого, ассоциированного объекта. Обычно используется в крньюкции с оассоциацией по первичному ключу.

5.1.4.2. Алгоритм Hi/Lo

Генераторы hilo и seqhilo предоставляют две альтернативные реализации алгортма hi/lo, наиболее предпочтительного подхода для генерации идентификаторов. Первая реализация требует "специальной" таблицы в базе данных, для хранения следующего "hi" значения. Вторая реализация использует последовательность (Oracle-style), в базах данных, которые их поддерживают.

hi_value next_value 100 hi_value 100

К сожалению вы не можете использовать hilo в случае поставки своего соединения (Connection) в Hibernate, так же невозможно его использование в конфигурации, когда Hiberante использует источник данных сервера приложений, управляемый JTA. Hiberante должен иметь возможность получать "hi" значение в новой тразакции. Стандартным подходом в EJB, является использование session stateless bean для реализации алгоритма hi/lo.

5.1.4.3. Алгоритм UUID

Не пробуйте использовать uuid.string в PostgreSQL.

5.1.4.4. Последовательности и identity колонки

Вы можете использовать генератор ключей identity для баз данных с поддержкой indentity столбцов (DB2, MySQL, Sybase, MS SQL). Для баз данных поддерживающих последовательности можно использовать sequence стиль для генерации ключей. Обе эти стратегии требуют двух SQL запросов для вставки нового объекта в базу данных.

uid_sequence

Для разработки кроссплатформеннох приложений используйте стратегию native. Она будет использвать identity, sequence и hilo стратегии в зависимости от возможностей той базы данных с которой в данный момент времени работает Hibernate.

5.1.4.5. Задаваемые идентификаторы

Если вы хотите чтобы приложение само назначало идетнификаторы, вы можете использовать генератор assigned. Этот специальный генератор использует идетнификаторы которые устанавливаются приложением. Для этого приложение устанавливает идентификатор в соответсвующее свойство объекта. Будте очень внимательны при использовании этой возможности для установки ключей (в большинстве случаев это решение сигнализирует о плохом дизайне приложения).

Вследствие свойственной ему природы, сущности которые используют этот генератор, не могут быть сохранены через метод Session.saveOrUpdate(). Вместо этого вы должны явно указывать Hibernate, должен ли объект быть создан или обновлен вызовами соотвествующих методов объекта Session: save() или update().

5.1.5. composite-id

......

Для таблиц с композитными ключами вы можете отображать несколько свойств класса как свойства идентификации объекта. Элемент принимает отображения свойств при помощи дочерних элементов и .

Ваш персистентный класс должен переопределять методы equals() и hashCode() для реализации эквивалентности композитных идентификаторов. Он так же должен реализовывать интерфейс Serializable.

К сожалению, возможность задавать составные идентификаторы подразумевает то, что персистентный объект и есть идентификатор. Нет возможности для удобной обработки, чем посредством самого объекта. Вы должны создать сущность персистентного класса самостоятельно и установить его идентифицирующее свойство перед тем как выполнить загрузку load() персистентного состояния ассоциированного с данным составным идентификатором. Мы опишем более подходящий способ, где составные идентификаторы реализованы отдельным классом в разделе Раздел 7.4, «Компоненты как составные идентификаторы» . Атрибуты, которые описываются ниже, применимы только для альтернативного метода:

    name (необязательно): свойство типа копонента, которое содержит составной идентификатор (см. следующий раздел).

    class (опционально, по умолчанию тип свойства определяет через рефлексию): компонент данного класса используется как составной идентификатор (см. следующий раздел).

    unsaved-value (опционально, по умолчанию none): если установлен в any, то это указывает на то, что транзитные сущности рассматриваются как новые.

5.1.6. discriminator

Элемент необходим для полиморфной персистентности, использующей стратегию отображения table-per-class-hierarchy. Данный элемент объявляет колонку-дискриминатор, по которой определяется соответствие записи в таблице конкретному классу в иерархии. Дискриминатор может иметь один из следующих типов: string, character, integer, byte, short, boolean, yes_no, true_false.

Соответствующие значения колонки дискриминатора для каждого класса задаются в атрибуте discriminator-value для элементов и .

Атрибут force полезен только в случае, если таблица содержит записи с дополнительными значениями дискриминатора, которые не отображаются в персистентном классе. Обычно данный атрибут не используется.

5.1.7. version (необязательно)

Элемент отражает то, что таблица содержит записи с пометкой о версии. Это особенно полезно, если вы планируете использовать длинные транзакции (см. ниже).

(1)

column (необязательно, по умолчанию берется имя свойства): имя колонки, которая хранит номера версий.

(2)

name: Имя свойства персистентного класса.

(3)

type (необязательно, по умолчанию integer): тип свойства версии.

(4)
(5)

unsaved-value (необязательно, по умолчанию undefined): Значение свойства версии, которое указывает на то, что сущность еще не сохранена (unsaved). Не путайте несохраненные сущности от транзитных, которые были сохранены или загружены в предыдущей сессии. (undefined указывает на то, что будет использовано значение идентификатора.)

Номера версий могут быть типа long, integer, short, timestamp либо calendar.

5.1.8. timestamp (необязательно)

Элемент указывает на то, что таблица содержит записи промаркированные временной меткой. Этот элемент выступает как альтернатива маркерам версии. Временные метки по определению менее безопасная реализация оптимистической блокировки. Тем не менее, иногда приложение использует временные метки для других целей

(1)

column (необязательно, по умолчанию используется имя свойства): имя колонки, которая содержит временную метку.

(2)

name: Имя в стиле JavaBeans типа Date или Timestamp свойства персистентного класса.

(3)

access (необязательно, по умолчанию property): стратегия, которую должен использовать Hibernate для доступа к значению свойства.

(4)

unsaved-value (необязательно, - по умолчанию null): Значение свойства времени, которое указывает на то, что сущность еще не сохранена (unsaved). Не путайте несохраненные сущности от транзитных, которые были сохранены или загружены в предыдущей сессии. (undefined указывает на то, что будет использовано значение идентификатора.)

Примечание: элемент эквивалентен элементу .

5.1.9. property

Элемент Объявляет персистентное, в стиле JavaBeans, свойство класса.

(1)

name: Имя свойства, начинается с буквы в нижнем регистре.

(2)

column (необязательно, по умолчанию подставляется название свойства): имя соответствующей колонки в таблице базы данных.

(3)

type (необязательно): название Hibernate-типа.

(4)

update, insert (необязательно, по умолчанию true) : указывает на то, что соответствующая колонка должна включаться в SQL-выражения UPDATE и/или INSERT. Установка обоих свойств в false позволяет задавать значение этого свойства либо из другого свойства, которое отображено в той же колонке/колонках, либо посредством триггера, либо другим приложением.

(5)

formula (необязательно): SQL-выражение, которое вычисляет значение свойства. Вычисляемые поля не должны отображаться в колонку таблиц базы данных.

(6)

access (необязательно, по умолчанию property): стратегия, которую Hibernate должен использовать для доступа к значению свойства.

значение свойства type может быть одним из следующих:

    Имя базового типа Hibernate (например, integer, string, character, date, timestamp, float, binary, serializable, object, blob).

    Имя Java-класса (например, int, float, char, java.lang.String, java.util.Date, java.lang.Integer, java.sql.Clob).

    Имя производного от PersistentEnum класса (например, eg.Color).

    Имя сериализуемого Java-класса.

    Имя пользовательского класса (например, com.illflow.type.MyCustomType).

Если вы не указываете значение свойства type, Hibernate будет использовать рефлексию для указанного свойства для подбора соответствующего Hibernate типа. Hibernate попытается определить имя класса возвращаемого свойства методом get() используя правила 2, 3, 4 в этом порядке. Тем не менее, этого не всегда бывает достаточно. В некоторых случаях вам все же необходимо указать атрибут type. (Например для различия между Hibernate.DATE и Hibernate.TIMESTAMP, либо для указания пользовательского типа.)

Атрибут access позволяет управлять задавать Hibernate метод доступа к полю во время исполнения. По умолчанию Hibernate вызывает методы get/set для доступа к полю. Если вы задаете access="field", то Hibernate будет обходить методы get/set и обращаться к полю напрямую, используя рефлексию. Вы можете указать вашу собственную стратегию для доступа указав класс, который реализует интерфейс net.sf.hibernate.property.PropertyAccessor.

5.1.10. many-to-one

Обычная связь с другим персистентным классов объявляется используя элемент many-to-one. В реляционных терминах это ассоциация многих к одному. В действительности это просто ссылка на объект.

(1)

name: Имя свойства.

(2)

column (необязательно): Имя колонки.

(3)

class (необязательно - по умолчанию тип поля определяется через рефлексию): Имя ассоциированного класса.

(4)

cascade (необязательно): Определяет, какая операция будет выполняться каскадом от родительского объекта к ассоциированному.

(5)
(6)

update, insert (необязательно - по умолчанию true) определяет то, что отображаемые колонки будут включены в SQL-запросы UPDATE и/или INSERT. Установка обоих свойств в false позволяет задавать значение этого свойства либо из другого свойства, которое отображено в той же колонке/колонках, либо посредством триггера, либо другим приложением.

(7)

property-ref: (необязательно) Имя ключевого свойства ассоциированного класса. По этому свойству будет происходить связывание (join). Если не указано, то используется первичный ключ ассоциированного класса.

(8)

access (необязательно - по умолчанию property): Стратегия, которую использует Hibernate для доступа к значению данного поля.

Атрибут cascade может принимать следующие значения: all, save-update, delete, none. Установка значения отличного от none повлечет определенные операции над ассоциированным (дочерним) объектом. См ниже "Жизненный цикл объектов".

Атрибут outer-join может принимать три следующих значения:

    auto (по умолчанию) извлекает ассоциированные объекты используя outer join если ассоциированный класс не имеет прокси.

    true Всегда извлекать ассоциированные объекты используя outer join.

    false Никогда не извлекать ассоциированные объекты используя outer join.

Типичное объявление ассоциации many-to-one выглядит так

Атрибут property-ref использоваться только для связи c унаследованными данными, когда внешний ключ ссылается на уникальное значение ассоциированной таблицы отличной от первичного ключа. Это опасное реляционное решение. Например, возможно, что класс Product имеет уникальный последовательный номер, который не является первичным ключем. (Атрибут unique конролирует герерацию DDL Hibernate"ом. Генерация производится при помощи утилиты SchemaExport.)

Отображение для OrderItem может использовать:

В действительности, так делать крайне не рекомендуется.

5.1.11. one-to-one

Ассоциация "один к одному" с другим персистентным классом можно объявить, используя элемент one-to-one.

(1)

name: Имя свойства.

(2)

class (необязательно - по умолчанию определяется рефлексией исходя из типа поля): Имя ассоциированного класса.

(3)

cascade (необязательно) определяет какая операция будет выполняться каскадом от родительского объекта к ассоциированному.

(4)

constrained (необязательно) определяет то, что внешний ключ, ссылающийся на таблицу ассоциированного класса, ограничен первичным ключом этой таблицы. Эта опция влияет на порядок, в котором выполняются каскадные операции save() и delete() (а так же используется утилитой экспортирующей схему - schema export tool).

(5)

outer-join (необязательно - по умолчанию auto): Задействует извлечение ассоциированных объектов, используя объединения outer-join если опция hibernate.use_outer_join конфигурационного файла включена.

(6)

property-ref: (необязательно) Имя свойства ассоциированного класса, которое входит в первичный ключ данного класса. Если не указано, то используется первичный ключ ассоциированного класса.

(7)

access (необязательно, по умолчанию property): Стратегия, которую должен использовать Hibernate для доступа к данному полю.

Существует два вида ассоциаций "один к одному":

    связь по первичному ключу

    связь по уникальному внешнему ключу

Для организации ассоциации по первичному ключу нет надобности в дополнительных столбцах; если две записи связаны такой ассоциацией, то это значит, что две записи в двух таблицах имеют одно и то же значение первичного ключа. Следовательно, если вы хотите ассоциировать два объекта, чтобы они были связаны по первичному ключу, то вы должны убедиться в том, что их идентификаторам присвоены одинаковые значения!

Для ассоциации по первичному ключу добавьте следующее отображение для классов Employee и Person соответственно.

Теперь мы должны убедиться в том, что первичные ключи связанных записей в таблицах идентичны. Мы используем специальный генератор Hibernate foreign:

employee ...

Сохраняемому экземпляру класса Person присваивается тоже значение первичного ключа, которое присвоено экземпляру класса Employee на который ссылается свойство employee класса Person.

Как альтернативный вариант описания связи "один к одному" от Employee к Person, через уникальный внешний ключ можно использовать следующую запись:

Эта ассоциация может быть двунаправленной после добавления следующего выражения к маппингу класса Person:

5.1.12. component, dynamic-component

Элемент отображает поля вложенного объекта на колонки таблицы родительского класса. Компоненты могут в свою очередь определять свои собственные свойства, компоненты или коллекции. Смотрите "Компоненты" ниже.

(5) ........

(1)

name: Наименование свойства (ссылающегося на компонентный объект).

(2)

class (необязательно - по умолчанию тип компонента определяется используя рефлексию): Наименование класса компонента.

(3)

insert: Если установлен в true, то отображаемые поля компонента участвуют в SQL-запросах INSERT.

(4)

update: Если установлен в true, то отображаемые поля компонента участвуют в SQL-запросах UPDATE.

(5)

access (необязательно - по умолчанию property): Стратегия, которую должен использовать Hibernate при доступе к этому компоненту через родительский объект.

Вложенные тэги Отображают поля компонента в колонки таблицы.

Элемент допускает вложенный элемент Который отображает свойство компонента как обратную ссылку на родительский объект.

Элемент позволяет использовать Map как компонент, в котором имена полей соответствуют ключам Map"а.

5.1.13. subclass

И наконец, полиморфная персистентность требует объявления каждого подкласса базового класса. Для (рекомендованной) стратегии отображения table-per-class-hierarchy используется элемент .

.....

Каждый подкласс должен объявлять свои собственные персистентные поля и подклассы. Допускается наследование свойств и от базового класса. Каждый подкласс в иерархии должен определять уникальное значение discriminator-value. Если это значение не указано, то в качестве дискриминатора используется полное имя класса.

5.1.14. joined-subclass

В качестве альтернативы, подкласс, объекты которого хранятся в отдельной таблице (стратегия отображения table-per-subclass), объявляется используя элемент .

.....

Для данной стратегии отображения не требуется указывать колонку discriminator. Однако, каждый подкласс должен объявлять колонку таблицы, которая содержит идентификатор отображаемый элементом . Маппинг приведенный в начале раздела может быть переписан следующим образом:

Персистентное состояние состоит из ссылок на другие сущности и экземляры типов-значения . Значения это примитивы, коллекции, компоненты и другие неизменяемые объекты. В отличии от сущностей экземляры типов значений (в частности коллекции и компоненты) сохраняются и удаляются по доступности. Поскольку объекты типов-значений (и примитивы) сохраняются и удаляются вместе с содержащей их сущностью они не могут иметь независимую версионность. Значения не имеют так же независимой идентификатоции и, таким образом, не могут быть разделены между двумя сущностями или коллекциями.

Все типы в Hibernate, за исключением коллекций, поддерживают семантику null-указателей.

До этого момента мы использовали термин "персистентный класс" для ссылки на сущности. Мы будем продолжать делать это. Строго говоря, не все определенные пользователем классы с персистентным состоянием являются сущностями. Например, компонент - это определенный пользователем класс с семантикой типа-значения (коспоненты, являются частью сущностей их содержащих, и считаются полями этих сущностей).

5.2.2. Базовые типы-значения

Базовые типы могут быть грубо разделены следующим образом

integer, long, short, float, double, character, byte, boolean, yes_no, true_false

Мапинги примитивных Java-типов либо классов оберток на соответсвующие (зависимые от поставщика) SQL-типы колонок таблиц. boolean, yes_no и true_false являются альтернативными обозначениями для Java-типов boolean или java.lang.Boolean.

string

Отображение типа java.lang.String в VARCHAR (либо Oracle VARCHAR2).

date, time, timestamp

Отображение типа java.util.Date и его подклассов в в SQL-типы DATE, TIME и TIMESTAMP (либо эквивалентные).

calendar, calendar_date

Отображение типа java.util.Calendar в SQL-типы TIMESTAMP и DATE (либо эквивалентные).

big_decimal

Отображение типа java.math.BigDecimal в NUMERIC (или Oracle NUMBER).

locale, timezone, currency

Отображение типа java.util.Locale, java.util.TimeZone и java.util.Currency в VARCHAR (или Oracle VARCHAR2). Экземпляры Locale и Currency отображаются в их ISO коды. Экземпляры TimeZone отображаются в их идентификаторы (ID).

class

Отображение типа java.lang.Class в VARCHAR (или Oracle VARCHAR2). Class отображается как его полное имя.

binary

Отображает массивы байтов в соответствующий бинарный SQL-тип.

text

Отображает длинные строки Java в SQL CLOB либо TEXT.

serializable

Отображает сериализуемые Java-типы в соответствующие бинарные SQL-типы. Вы так же можете обозначить Hibernate-типом serializable имя сериализуемого Java-класса либо интерфейса, который не является базовым типом и не реализует интерфейс PersistentEnum.

clob, blob

Отображение типа JDBC классов java.sql.Clob и java.sql.Blob. Эти типы могут быть неудобными для некоторых приложений, так как объекты типов blob и clob не могут использоваться вне транзакций. (К тому же, драйвера поддерживают эти типы не полностью и неодинаково.)

Уникальные идентификаторы сущностей и коллекций могут быть любого базового типа за исключением binary, blob и clob. (Составные идентификаторы так же допускаются, смотри ниже.)

Базовые типы-значения описываются константами объявленными в net.sf.hibernate.Hibernate. Например, Hibernate.STRING представляет тип string.

5.2.3. Персистентные перечисляемые типы (enum)

Перечисляемый тип является базовой идиомой Java когда класс имеет константное (небольшое) количество неизменяемых экземляров (прим. переводчика в Java 5 это введено на уровне языка, в более ранних версиях для этого применялся специальных паттерн). Вы можете создавать персистентные перечисляемые типы реализуя интерфейс net.sf.hibernate.PersistentEnum, и определяя операции toInt() и fromInt():

Package eg; import net.sf.hibernate.PersistentEnum; public class Color implements PersistentEnum { private final int code; private Color(int code) { this.code = code; } public static final Color TABBY = new Color(0); public static final Color GINGER = new Color(1); public static final Color BLACK = new Color(2); public int toInt() { return code; } public static Color fromInt(int code) { switch (code) { case 0: return TABBY; case 1: return GINGER; case 2: return BLACK; default: throw new RuntimeException("Unknown color code"); } } }

Имя Hibernate-типа - это просто имя перечисляемого класса, в данном случае eg.Color.

5.2.4. Пользовательские типы-значения

Для разработчиков относительно просто создать свои типы-значения. Например, вы можете захотеть сохранять свойства типа java.lang.BigInteger в колонки типа VARCHAR. Hibernate не предоставляет встроенного типа для этого. Но определение пользовательских типов не огранивается отображением свойств (либо элементов коллекций) в единичный столбец таблицы. Таким образом, например, вы можете иметь свойство getName()/setName() типа java.lang.String которое хранится в колонках FIRST_NAME, INITIAL, SURNAME.

Для реализации пользовательского типа, реализуйте один из интерфесов net.sf.hibernate.UserType либо net.sf.hibernate.CompositeUserType и объявите свойство, используя полное имя класса вашей реализации типа. Просмотрите net.sf.hibernate.test.DoubleStringType для уточнения доступных возможностей.

Примечание: используйте тэги для отображения свойства в несколько колонок.

Хотя богатство встроенных Hibernate-типов и поддержка компонентов подразумевает то, что нужда в использовании пользовательских типов возникает достаточно редко, все же считается хорошей практикой использование последних в качестве (не сущностных) классов для типов, часто используемых в вашем приложении. Например, класс MonetoryAmount хороший кандидат для CompositeUserType, хотя он может отображаться как компонент. Главная мотивация это абстракция. С пользователскими типами, ваш документ маппинга будет более усточивым к возможным изменениям в будущем в случае если вы измените представление денежного типа.

5.2.5. Отображение Any типа

Есть еще один тип для отображения свойств. Элемент отображения объявляет полиморфную ассоциацию для классов из нескольких таблиц. Этот тип отображения всегда требует более одной колонки. Первая колонка содержит тип ассоциированной сущности. Остальные колонки содержат идентификатор. Невозможно пределить внешний ключ для данного типа ассоциации, таким образом, это отображение обычно не используется для полиморфных ассоциаций. Вы должны использовать подобное отображение только в особых случаях (например, запись разнотипных данных, обращение к данным пользовательской сессии).

Атрибут meta-type позволяет приложению задать пользовательский тип, который отображает значения колонок базы данных в персистентные классы, свойства-идентификаторы которых имеют тип, определеный в id-type. Если мета-тип (meta-type) возвращает сущности java.lang.Class, то больше ничего не требуется. В остальных случаях, когда это базовый тип, такой как string или character вы должны определить соответствие значений классам.

..... .....

(1)

name: Имя свойства.

(2)

id-type: Тип идентификатора.

(3)

meta-type (необязательно - по умолчанию class): тип, который отображает java.lang.Class в одну колонку базы данных либо, в качестве альтернативы, тип, который разрешен для отображения дискриминатора.

(4)

cascade (необязательно - по умолчанию none): тип каскадной операции.

(5)

access (необязательно - по умолчанию property): Стратегия, которую должен использовать Hibernate для доступа к значению свойства.

Старое свойство object, которое занимает отдельное место в Hibernate 1.2, все еще поддерживается, но объявлено полу-устаревшим.

5.3. SQL-идентификаторы в кавычках

Вы можете принудить Hibernate заключать идентификаторы в кавычки в SQL выражениях. Hibernate будет следовать правилам заключения в кавычки согласно установленного диалекта SQL (обычно двойные кавычки, но скобки для SQL Server и обратные кавычки для MySQL).

...

5.4. Отдельные файлы отображения

Можно объявлять отображения subclass и joined-subclass в отдельных документах, прямо внутри элемента hibernate-mapping. Это позволяет расширять иерархию классов добавлением нового файла отображения. При таком подходе вы должны указать атрибут extends в отображении подкласса, содержащий имя предварительно замапленного суперкласса. Использование данной возможности делает важным порядок перечисления документов отображений.

Дорогие друзья!

Сегодня мы рады сообщить вам о том, что наши разработчики реализовали возможность транспортировки данных по URL (mapping, мэппинг) за “пределы” целевой страницы.

С помощью данной функции можно передать все данные с полей формы на страницу, на которую переходит пользователь, отправляя вам лид. Благодаря этому, лид попадает не только во , но также может попасть сразу и в вашу базу, если на странице редиректа его “встретит” соответствующий скрипт.

Теперь нет необходимости в экспорте данных из системы обработки лидов! Вы можете отправлять и обрабатывать их сразу в собственной базе!

Так же, благодаря данной функции, становится возможным поздравить или поблагодарить пользователя, предоставившего свои контактные данные лично.

Как работает мэппинг (mapping)?

Суть мэппинга в том, что при отправке данных с полей формы, в ссылку, по которой происходит переадресация, добавляются их содержимое. URL приобретает вид: //my_site.com/?name=ИМЯ&email=АДРЕС_ЭЛЕКТРОННОЙ _ПОЧТЫ&phone=НОМЕР_ТЕЛЕФОНА&lead_id=225298.

Важно! В дополнение ко всем данным полей, всегда передается ID лида в параметре lead_id.

На странице же, на которую осуществоляется переход, данную информацию “принимает” специальный скрипт, который, в свою очередь, распределяет данные по соответствующим “ячейкам”.

Обращаем ваше внимание! Мэппинг работает только в том случае, если “Результат формы” - “Переход по URL”!

Как настроить “транспортировку” лида по URL (mapping) на моей целевой странице?

1. Войдите в .
2. Выберите страницу с формой лида, с которой вы собираетесь “транслировать” данные.

3. В редакторе сделайте двойной щелчок по форме.

4. В появившемся окне заполните графу “Mapping” соответствующими названиями полей на английском языке. Например,name - имя, phone - телефон и т. п.

5. Сохраните изменения.

6. В свойствах формы настройте редирект на нужную страницу - это может быть или страница вашего сайта, в которую встроен JavaScript, который и будет обрабатывать данные с полей, поступившие с URL.

Установите флажок в чекбоксе “Передать поля формы”.

7. Сохраните изменения в основном меню редактора.

Вот и все! :-)

Теперь данные с полей вашей формы будут передаваться на страницу, на которую вы переадресовываете пользователя. Вам не придется экспортировать лиды из CRM LPgenerator - они могут “транспортироваться” в вашу CRM прямо по URL. Возможности мэппинга (mapping) по транспортировке данных воистину безграничны.

Компании, применяющие Excel для целей трансформации отчетности, получают ощутимую экономию при подготовке отчетности по МСФО. Если объемы транзакций позволяют обрабатывать учетные данные в электронных таблицах, целесообразно использовать Excel

12.01.2016

Таблицы Excel помимо арифметической точности и наглядности процедур трансформации позволяют формировать данные для экономического анализа финансовой деятельности на основании результатов по МСФО, что превращает модель отчетности в инструмент управления.

Подготовительный этап трансформации отчетности

На подготовительном этапе осуществляется анализ конкретных различий между МСФО, применимых к данной компании, и учетной практикой по РСБУ. Следует отметить, что нецелесообразно отталкиваться от правил российского учета, поскольку в данном случае сложно будет уйти от «приоритета формы над содержанием», - начинать следует с анализа компании в целом и ее деятельности с точки зрения МСФО.

Международные стандарты, имеющие отношение к каждому конкретному бизнесу, должны быть включены в состав учетной политики по МСФО. Например, торговое предприятие вряд ли будет использовать сложные финансовые инструменты или положения МСФО (IAS) 41 «Сельское хозяйство», а частная компания не должна раскрывать прибыль на акцию в соответствии с МСФО (IAS) 33 «Прибыль на акцию». Процедура формирования учетной политики должна быть нацелена не только на создание правил и меморандумов учета в соответствии с МСФО, но и на подготовку блока примечаний непосредственно отчетности по МСФО, содержащего основные аспекты учетной политики, обязательные к раскрытию в соответствии с МСФО (IAS) 1 «Представление финансовой отчетности».

Основываясь на полученной учетной политике по МСФО, следует выявить расхождения в оценках и принципах, применяемых в РСБУ, и сформировать список и правила расчета основных трансформационных корректировок, а также перечень дополнительной информации, необходимой для целей МСФО, но не учитываемой в соответствии с требованиями российского законодательства.

При первом применении международных стандартов в соответствии с МСФО (IFRS) 1 следует помнить об исключениях и упрощениях, разрешенных стандартом, и о том, что в дальнейшем данные послабления перестают действовать.

Процесс обновления учетной политики по МСФО, списка корректировок и перечня дополнительной информации должен быть постоянным, поскольку требования МСФО и российского законодательства постоянно дополняются.

Мэппинг плана счетов для трансформации отчетности

Мэппинг - от английского mapping (соответствие, а также преобразование) - это процедура разноски данных в нескольких системах координат, в нашем случае конвертация остатков и оборотов, сформированных в соответствии с планом счетов РСБУ, в структуру плана счетов по МСФО (таблица 1).

Таблица 1. Пример мэппинга плана счетов

Несколько слов о составлении собственно плана счетов по МСФО.

  • Каждый показатель МСФО должен обладать уникальным цифровым кодом, в крайнем случае буквенно-цифровым, строго определенного формата. Суммирование показателей в современных версиях Excel возможно даже по текстовым признакам, однако в таком случае возрастает риск искажения данных в случае простой опечатки. Для сведения ошибок к минимуму применяются справочники и выпадающие списки с кодами и наименованиями счетов и аналитик, а также формулы «СУММЕСЛИ» и «ВПР», суммирующие данные с заданными признаками, а именно уникальными кодами.
  • Иерархия плана счетов должна позволять группировать данные не только по элементам, но также по строкам отчетной формы и примечаниям. Допустим, статья «Здания и сооружения - Первоначальная стоимость» помимо собственного кода должна также содержать среди аналитик код строки отчета о финансовом положении (далее по тексту - баланс) и код таблицы примечаний, что позволит заполнять формы и табличные примечания отчетности с помощью формул Excel.
  • Каждый раздел форм отчетности в плане счетов должен содержать запасные пустые строки - это дает возможность гибко корректировать план счетов без перенастройки формул, а также позволяет не нарушить принцип сопоставимости данных. Целесообразно предусмотреть место и для новых разделов, например, если компания ранее не имела инвестиционной собственности, но руководство планирует создание или приобретение недвижимого имущества для сдачи в аренду. В таком случае просто заполняются свободные строки и проставляются коды отчетности, а Excel автоматически агрегирует показатели.
  • Необходимо сохранять историю внесения изменений в мэппинг (как правило, на основании меморандума или иного распорядительного методологического документа) с указанием причины, ответственного лица, сроков вступления изменений в силу. Это важно как для формирования сопоставимых данных из периода в период, так и для прохождения аудита.

Следует отметить, что чем больше аналитик содержит российский план счетов, тем проще осуществлять мэппинг и реклассификационные корректировки, необходимые в связи с различными принципами агрегации данных в РСБУ и МСФО. Поэтому по возможности следует максимально приблизить план счетов РСБУ и его аналитику к нуждам МСФО, чтобы повысить эффективность процесса трансформации и снизить издержки.

Сбор информации, необходимой для заполнения трансформационной модели. На данном этапе собираются данные по остаткам балансовых счетов и оборотам доходно-расходных счетов за отчетный период, заполняется исходный баланс и отчет о прибылях и убытках.

Одновременно с этим процессом анализируются существенные операции, судебные споры, крупные новые контракты, дополнительные раскрытия. Должен быть разработан регламентированный перечень дополнительной информации, а также назначены ответственные за подготовку соответствующих данных и установлены сроки исполнения.

Перечень, представленный в таблице 2, может быть как сокращен, если у компании отсутствуют те или иные операции, так и существенно расширен. Как правило, в деятельности компании изменения, влекущие дополнительные корректировки по МСФО, возникают редко. Поэтому наиболее тщательный анализ делается во время первичного ознакомления с бизнесом, а уже затем отслеживаются существенные изменения. Таким образом, в большинстве случаев компании должны составлять порядка десяти-двадцати трансформационных корректировок, которые могут быть регламентированы соответствующими методическими указаниями и закреплены в документе «Порядок учета трансформационных корректировок».

Таблица 2. Примерный перечень дополнительной информации

Все корректировки следует оформлять в виде рабочего документа наподобие бухгалтерской справки. Рабочий документ должен содержать методологические основы и фактические предпосылки, на основании которых были сделаны те или иные корректировки, и непосредственно сами расчеты. Также необходимо установить контрольные процедуры, направленные на проверку правильности расчетов, сверку данных рабочих документов и трансформационных моделей, а также корректности проводок.

Этап формирования входящих корректировок . Входящие корректировки формируются при первом применении МСФО, а также при сделках по приобретению новых компаний, которые должны оцениваться по справедливой стоимости.

Для начала осуществляется перегруппировка статей баланса и отчета о прибылях и убытках. Это так называемые реклассификационные корректировки. К основным реклассификационным корректировкам относятся разворачивание или сворачивание дебиторской и кредиторской задолженности и авансов, рекласс расходов будущих периодов, разделение краткосрочных и долгосрочных активов и обязательств, перенос депозитов со сроком погашения менее 90 дней в денежные средства, а также более детальная разноска доходов и расходов на соответствующие счета, если подобная работа не была сделана на этапе мэппинга (таблица 3).

Таблица 3. Пример реклассификационной таблицы

Следующий блок корректировок - это исправления, влияющие на величину статей баланса, а также доходов и расходов. Следует не смешивать их с реклассификационными корректировками, поскольку только расчетные корректировки влияют на величину отложенных налогов по МСФО.

На практике наиболее существенные суммы корректировок связаны с оценкой активов по справедливой стоимости - основных средств (особенно в случаях, когда компания владеет старыми фондами) и нематериальных активов. Своими силами рассчитать подобные корректировки невозможно, поскольку для этого необходимы данные отчета об экспертизе, проведенной квалифицированным оценщиком. Например, без специальных знаний и опыта невозможно определить стоимость клиентской базы, которая при покупке компании должна признаваться в качестве нематериального актива по МСФО. Только после получения данных оценки о справедливой сумме первоначальной стоимости, степени износа, оставшегося полезного срока использования формируются реестры основных средств и нематериальных активов по МСФО. Учет основных средств и нематериальных активов может осуществляться как в отдельной программе, так и в электронных таблицах, когда в Excel ведется реестр основных средств, отражаются поступления, модернизации, выбытия объектов, рассчитывается амортизация по стоимости, признанной в соответствии с МСФО.

Наиболее простой способ расчета корректировок заключается в сопоставлении данных РСБУ и МСФО и определении расхождения между ними. Данные суммы и формируют поправку (таблица 4).

Таблица 4. Расчет корректировки по дооценке основных средств по справедливой стоимости

Помимо отражения переоценки, по основным средствам и нематериальным активам бывает необходимо пересчитывать сумму капитализированных процентов, поскольку РСБУ и МСФО содержат разные подходы при определении суммы капитализации.

Положения стандарта МСФО (IAS) 36 «Обесценение активов» также в большей степени направлены на тестирование основных средств и нематериальных активов, чья стоимость должна корректироваться при наличии признаков обесценения.

Если компания использует инструменты финансовой аренды в своей деятельности (в том аспекте, как ее интерпретируют МСФО), поправки также могут затрагивать сумму основных средств и расходов по амортизации, в корреспонденции с обязательствами по финансовой аренде и задолженности по процентам за пользование кредитными средствами.

Особое внимание стоит уделять корректировкам, связанным с дисконтированием (как, например, в случае с долгосрочной финансовой арендой, когда на основе дисконтирования оценивается и стоимость основных средств, и задолженность по договорам финансовой аренды). В МСФО требуется дисконтировать любые долгосрочные активы и обязательства:

  • суммы выручки, когда оплата отсрочена во времени;
  • величина долгосрочного резерва или оценочного обязательства в соответствии с МСФО (IAS) 37 «Резервы, условные обязательства и условные активы»;
  • стоимость инвестиции в дочернюю компанию, когда предусмотрена отложенная оплата за акции;
  • долговой компонент долгосрочных конвертируемых облигаций;
  • возмещаемая стоимость финансового актива, учитываемого по амортизированной стоимости, при тестировании его на обесценение и т.д.

Среди наиболее часто встречающихся корректировок можно также отметить:

  • по запасам (списание в убытки неликвидных запасов, создание резерва под обесценение запасов, списание на расходы недостач и потерь от порчи ценностей, а также некоторых видов расходов будущих периодов);
  • по расчетам с персоналом (корректировки резервов по отпускам, создание резерва по будущим вознаграждениям, расчеты по пенсионным планам);
  • Cutoff-корректировки (списание отложенной выручки, доначисление или списание доходов и расходов отчетного периода, которые не были отражены в РСБУ по причине отсутствия документов или различий в подходе признания момента перехода рисков и выгод, в корреспонденции со счетами расчетов с контрагентами);
  • по дебиторской и кредиторской задолженности, а также кредитам и займам (отражение по амортизированной стоимости с использованием метода эффективной ставки процента, корректировка резервов по сомнительным долгам);
  • по финансовым вложениям (признание доли в прибыли или убытке ассоциированных компаний, корректировки стоимости финансовых вложений, по которым можно определить текущую рыночную стоимость, и т.д.).

После формирования всех расчетных поправок определяется сумма корректировки отложенного налога на прибыль.

Конечно же, перечислены далеко не все возможные корректировки, поскольку задача состоит в том, чтобы продемонстрировать, каким образом формируется пул входящих корректировок и как корректировки должны переноситься из года в год (таблица 5).

Таблица 5. Формирование списка входящих корректировок

Далее с учетом входящих корректировок осуществляется подготовка баланса, отчета о прибылях и убытках, отчета об изменении капитала, отчета о движении денежных средств в формате МСФО, а также выполняется подготовка пояснений к отчетности.

Первичные корректировки используются для переноса в отчетность следующих периодов в качестве входящих поправок. Существует два способа переноса:

  • учитываются корректировки балансовых счетов в корреспонденции со счетом нераспределенной прибыли;
  • сторнируются корректировки доходно/расходных счетов в корреспонденции со счетом нераспределенной прибыли.

Выбор метода переноса влияет только на технику расчета текущих корректировок для следующих отчетных периодов, конечный результат будет одинаков, однако поменять модель расчета корректировок уже будет нельзя, поэтому следует заранее определить наиболее удобный метод и придерживаться его.

Этап формирования корректировок для последующих отчетных периодов . Типовые корректировки в следующих отчетных периодах необходимо составлять с учетом входящих корректировок. Механизм формирования данных МСФО заключается в следующем - в таблицах Excel заполняются постранично:

  • мэппинг остатков и оборотов по РСБУ в остатки и обороты по МСФО;
  • реклассификационные корректировки;
  • входящие корректировки (без учета реклассов предыдущего периода);
  • корректировки текущего периода (рассчитываются в отдельных рабочих документах с учетом накопленных входящих корректировок).

Затем с помощью формул «СУММЕСЛИ» подтягиваются данные на сводный лист (см. таблицу 6).

Таблица 6. Формирование данных МСФО в трансформационной модели

Данные МСФО (столбец 8) получаются путем суммирования исходных данных РСБУ, реклассифицирующих, входящих и текущих корректировок. На следующем этапе также с помощью формулы «СУММЕСЛИ» готовые показатели МСФО агрегируются на страницах отчетов (баланса, отчета о прибылях и убытках) по кодам строк форм отчетности в соответствии с присвоенным кодом формы отчетности (таблица 7). Аналогичным образом заполняются табличные формы примечаний, прописываются контрольные и сверочные формулы между трансформационной таблицей, формами отчетности и примечаниями, сопоставляется изменение нераспределенной прибыли за период с начальным и конечным сальдо по показателю (возможны расхождения на сумму начисленных дивидендов).

Таблица 7. Пример использования функции Excel «СУММЕСЛИ»

Как мы видим, Excel позволяет достаточно просто и наглядно формировать данные МСФО путем трансформации. На практике применяются и другие подходы к заполнению трансформационных таблиц, например, наподобие классической шахматки. Однако если корректировок много, получаются громоздкие файлы и возрастает риск технических ошибок, более того, становится сложно анализировать накопленные за несколько периодов поправки. Какая бы ни применялась модель трансформации, существуют универсальные рекомендации по работе с Excel: должно быть организовано хранение данных на надежных и защищенных от постороннего доступа серверах, автоматическое создание резервных копий основных рабочих файлов и автосохранение в процессе работы, регулярное архивирование как первичных данных, так и финальных моделей, отслеживание внесения изменений в файлы и ведение сводного файла-статуса (контрольного листа), содержащего информацию о необходимых этапах выполнения трансформации и степени выполнения установленных процедур.


В предыдущей части были рассмотрены виды связей (один-к-одному, один-ко-многим, многие-ко-многим), а также один класс Book и его маппинг-класс BookMap. Во второй части обновим класс Book, создадим остальные классы и связи между ними, как это было изображено в предыдущей главе в Диаграмме баз данных, расположившейся над подзаголовком 1.3.1 Связи.

Код классов и маппингов (С комментариями)

Класс Книга

Public class Book { //Уникальный идентификатор public virtual int Id { get; set; } //Название public virtual string Name { get; set; } //Описание public virtual string Description { get; set; } //Оценка Мира фантастики public virtual int MfRaiting { get; set; } //Номера страниц public virtual int PageNumber { get; set; } //Ссылка на картинку public virtual string Image { get; set; } //Дата поступления книги (фильтр по новинкам!) public virtual DateTime IncomeDate { get; set; } //Жанр (Многие-ко-Многим) //Почему ISet а не IList? Только одна коллекция (IList) может выбираться с помощью JOIN выборки, если нужно более одной коллекции для выборки JOIN, то лучше их преобразовать в коллекцию ISet public virtual ISet Genres { get; set; } //Серия (Многие-к-одному) public virtual Series Series { get; set; } //Мнение и другое (Один-к-одному) private Mind _mind; public virtual Mind Mind { get { return _mind ?? (_mind = new Mind()); } set { _mind = value; } } //Автор (Многие-ко-многим) public virtual ISet Authors { get; set; } //Заранее инициализируем, чтобы исключение null не возникало. public Book() { //Неупорядочное множество (в одной таблице не может присутствовать две точь-в-точь одинаковые строки, в противном случае выбирает одну, а другую игнорирует) Genres = new HashSet(); Authors = new HashSet(); } } //Маппинг класса Book public class BookMap: ClassMap { public BookMap() { Id(x => x.Id); Map(x => x.Name); Map(x => x.Description); Map(x => x.MfRaiting); Map(x => x.PageNumber); Map(x => x.Image); Map(x => x.IncomeDate); //Отношение многие-ко-многим HasManyToMany(x => x.Genres) //Правила каскадирования All - Когда объект сохраняется, обновляется или удаляется, проверяются и //создаются/обновляются/добавляются все зависимые объекты.Cascade.SaveUpdate() //Название промежуточной таблицы ДОЛЖНО быть как и у класса Genre! .Table("Book_Genre"); HasManyToMany(x => x.Authors) .Cascade.SaveUpdate() .Table("Book_Author"); //Отношение многие к одному References(x => x.Series); //Отношение один-к-одному. Главный класс. HasOne(x => x.Mind).Cascade.All().Constrained(); } }

Public class Author { public virtual int Id { get; set; } //Имя-Фамилия public virtual string Name { get; set; } //Биография public virtual string Biography { get; set; } //Книжки public virtual ISet Books { get; set; } //Инициализация Авторов public Author() { Books=new HashSet(); } } //Маппинг Автора public class AuthorMap: ClassMap { public AuthorMap() { Id(x => x.Id); Map(x => x.Name); Map(x => x.Biography); //Отношение многие-ко-многим HasManyToMany(x => x.Books) //Правила каскадирования All - Когда объект сохраняется, обновляется или удаляется, проверяются и создаются/обновляются/добавляются все зависимые объекты.Cascade.All() //Владельцем коллекции явл. другой конец отношения (Book) и он будет сохранен первым. .Inverse() //Название промежуточной таблицы ДОЛЖНО быть как и у класса Book! .Table("Book_Author"); } }

Класс Жанр

Public class Genre { public virtual int Id { get; set; } //Название жанра public virtual string Name { get; set; } //Английское название жанра public virtual string EngName { get; set; } //Книжки public virtual ISet Books { get; set; } //Инициализация книг public Genre() { Books=new HashSet(); } } //Маппинг жанра public class GenreMap: ClassMap { public GenreMap() { Id(x => x.Id); Map(x => x.Name); Map(x => x.EngName); //Отношение многие-ко-многим HasManyToMany(x => x.Books) //Правила каскадирования All - Когда объект сохраняется, обновляется или удаляется, проверяются и создаются/обновляются/добавляются все зависимые объекты.Cascade.All() //Владельцем коллекции явл. другой конец отношения (Book) и он будет сохранен первым. .Inverse() //Название промежуточной таблицы ДОЛЖНО быть как и у класса Book! .Table("Book_Genre"); } }

Класс Мнение:

Public class Mind { public virtual int Id { get; set; } //Мое мнение public virtual string MyMind { get; set; } //Мнение фантлаба public virtual string MindFantLab { get; set; } //Книга public virtual Book Book { get; set; } } //Маппинг Мind public class MindMap:ClassMap { public MindMap() { Id(x => x.Id); Map(x => x.MyMind); Map(x => x.MindFantLab); //Отношение один к одному HasOne(x => x.Book); } }

Класс Цикл(Серия):

Public class Series { public virtual int Id { get; set; } public virtual string Name { get; set; } //Я создал IList, а не ISet, потому что кроме Book, Series больше ни с чем не связана, хотя можно сделать и ISet public virtual IList Books { get; set; } //Инициализация книг. public Series() { Books = new List(); } } public class SeriesMap: ClassMap { public SeriesMap() { Id(x => x.Id); Map(x => x.Name); //Отношение один-ко-многим HasMany(x => x.Books) ////Владельцем коллекции явл. другой конец отношения (Book) и он будет сохранен первым. .Inverse() } }

Небольшое объяснение
public virtual ISet Genres { get; set; }
public virtual ISet Authors { get; set; }

Почему ISet, а не, к примеру, привычный многим IList? Если использовать вместо ISet - IList, и попробовать запустить проект, то разницы особой мы не заметим (Таблицы и классы создадутся). Но когда мы к классу Book LeftJoin-им одновременно таблицу Genre и Authors, да и еще пытаемся вывести неповторяющиеся записи из таблицы Book (Distinct Book.Id) в представление (View), Nhibernate выдаст исключение и ошибку.
Cannot simultaneously fetch multiple bags.
В таких случаях используем ISet, тем более множества для этого и предназначены (игнорируют дублирующие записи).

Отношение многие-ко-многим.

В NHibernate есть понятие, «главной» таблицы. Хотя отношения «многие-ко-многим» между таблицами “Book” и “Автор” равнозначны (У автора может быть много книг, у книги может быть множество авторов), Nhibernate требует, чтобы программист указывал таблицу, которая сохраняется второй (имеет метод.inverse()), то есть вначале будет создана/обновлена/удалена запись в таблице Book, а только потом в таблице Author.
Cascade.All означает выполнение каскадных операций при save-update и delete. То есть когда объект сохраняется, обновляется или удаляется, проверяются и создаются/обновляются/добавляются все зависимые объекты (Ps. Можно прописать вместо Cascade.All -> .Cascade.SaveUpdate().Cascade.Delete())
Метод.Table(«Book_Author»); создает «промежуточную» таблицу “Book_Author” в БД.

Отношение многие-к-одному, один-ко-многим.

Метод.Constrained() говорит NHibernate, что для записи из таблицы Book должна соответствовать запись из таблицы Mind (id таблицы Mind должен быть равен id таблицы Book)

Если сейчас запустить проект и посмотреть БД Bibilioteca, то появятся новые таблицы с уже сформированными связями.

Далее заполним созданные таблицы данными…
Для этого создадим тестовое приложение, которое будет сохранять данные в БД, обновлять и удалять их, изменив HomeController следующим образом (Ненужные участки кода комментируем):
public ActionResult Index() { using (ISession session = NHibernateHelper.OpenSession()) { using (ITransaction transaction = session.BeginTransaction()) { //Создать, добавить var createBook = new Book(); createBook.Name = "Metro2033"; createBook.Description = "Постапокалипсическая мистика"; createBook.Authors.Add(new Author { Name = "Глуховский" }); createBook.Genres.Add(new Genre { Name = "Постапокалипсическая мистика" }); createBook.Series = new Series { Name = "Метро" }; createBook.Mind = new Mind { MyMind = "Постапокалипсическая мистика" }; session.SaveOrUpdate(createBook); //Обновить (По идентификатору) //var series = session.Get(1); //var updateBook = session.Get(1); //updateBook.Name = "Metro2034"; //updateBook.Description = "Антиутопия"; //updateBook.Authors.ElementAt(0).Name = "Глуховский"; //updateBook.Genres.ElementAt(0).Name = "Антиутопия"; //updateBook.Series = series; //updateBook.Mind.MyMind = "11111"; //session.SaveOrUpdate(updateBook); //Удаление (По идентификатору) //var deleteBook = session.Get(1); //session.Delete(deleteBook); transaction.Commit(); } Genre genreAl = null; Author authorAl = null; Series seriesAl = null; Mind mindAl = null; var books = session.QueryOver() //Left Join с таблицей Genres .JoinAlias(p => p.Genres, () => .JoinAlias(p => p.Authors, () => authorAl, JoinType.LeftOuterJoin) .JoinAlias(p => p.Series, () => seriesAl, JoinType.LeftOuterJoin) .JoinAlias(p => p.Mind, () => mindAl, JoinType.LeftOuterJoin) //Убирает повторяющиеся id номера таблицы Book. .TransformUsing(Transformers.DistinctRootEntity).List(); return View(books); } }

Небольшое объяснение

  1. var books = session.QueryOver() Select * From Book ;
  2. .JoinAlias(p => p.Genres, () => genreAl, JoinType.LeftOuterJoin) - подобно выполнению скрипта SQL:
    SELECT *FROM Book
    inner JOIN Book_Genre ON book.id = Book_Genre.Book_id
    LEFT JOIN Genre ON Book_Genre.Genre_id = Genre.id
  3. .TransformUsing(Transformers.DistinctRootEntity) - Подобно выполнению скрипта SQL: SELECT distinct Book.Id... , (убирает дублирующие записи с одинаковыми id)

Виды объединений
.JoinAlias(p => p.Genres, () => genreAl, JoinType.LeftOuterJoin)

  1. LeftOuterJoin - выбирает все записи из левой таблицы (Book ), а затем присоединяет к ним записи правой таблицы (Genre ). Если не найдена соответствующая запись в правой таблицы, отображает её как Null
  2. RightOuterJoin действует в противоположность LEFT JOIN - выбирает все записи из правой таблицы (Genre ), а затем присоединяет к ним записи левой таблицы (Book )
  3. InnerJoin - выбирает только те записи из левой таблиц (Book ) у которой есть соответствующая запись из правой таблицы (Genre ), а затем присоединяет к ним записи из правой таблицы

Изменим представление следующим образом:

Представление index

@model IEnumerable @{ Layout = null; } Index

@Html.ActionLink("Create New", "Create")

@foreach (var item in Model) { @{string strSeries = item.Series != null ? item.Series.Name: null;} }
@Html.DisplayNameFor(model => model.Name) @Html.DisplayNameFor(model => model.Mind) @Html.DisplayNameFor(model => model.Series) @Html.DisplayNameFor(model => model.Authors) @Html.DisplayNameFor(model => model.Genres) Операции
@Html.DisplayFor(modelItem => item.Name) @Html.DisplayFor(modelItem => item.Mind.MyMind)@Html.DisplayFor(modelItem => strSeries) @foreach (var author in item.Authors) { string strAuthor = author != null ? author.Name: null; @Html.DisplayFor(modelItem => strAuthor)
}
@foreach (var genre in item.Genres) { string strGenre = genre!= null ? genre.Name: null; @Html.DisplayFor(modelItem => strGenre)
}
@Html.ActionLink("Edit", "Edit", new { id = item.Id }) | @Html.ActionLink("Details", "Details", new { id = item.Id }) | @Html.ActionLink("Delete", "Delete", new { id = item.Id })


Проверив поочередно все операции, мы заметим, что:
  • При операциях Create и Update обновляются все данные, связанные с таблицей Book (уберите Cascade=«save-update» или cascade=«all» и связанные данные не будут сохранены)
  • При удалении удаляются данные из таблиц Book, Mind, Book_Author, а остальные данные не удаляются, потому что у них Cascade=«save-update»

Маппинг для классов, у которых есть наследование.
А как маппить классы у которых есть наследование? Допустим, имеем такой пример:
//Класс Двумерных фигур public class TwoDShape { //Ширина public virtual int Width { get; set; } //Высота public virtual int Height { get; set; } } //Класс треугольник public class Triangle: TwoDShape { //Идентификационный номер public virtual int Id { get; set; } //Вид треугольника public virtual string Style { get; set; } }

В принципе, ничего сложного в этом маппинге нет, мы просто создадим один маппинг для производного класса, то есть таблицы Triangle.
//Маппинг треугольника public class TriangleMap: ClassMap { public TriangleMap() { Id(x => x.Id); Map(x => x.Style); Map(x => x.Height); Map(x => x.Width); } }
После запуска приложения, в БД Biblioteca появится следующая (пустая) таблица

Теги:

  • asp.net mvc 4
  • nhibernate
  • sql server
Добавить метки