Что такое port mapping? Формирование отчетности компании с использованием «мэппинга.
Проблема
Вы выгрузили бухгалтерский отчет о затратах и хотите продемонстрировать его руководству. Для этого вам необходимо скомпоновать данные статей бухгалтерского учета - по статьям управленечского учета. Вы знаете, как соотносятся между собой статьи БУ и УУ, но каждый раз подготовка такого отчета вручную у вас занимает слишком много времени.
Решение
Будем рассматривать данный кейс как продолжение предыдущего. Представим себе, что вы создали в Excel такой справочник:
Рис.2.1. Справочник: мэппинг статей БУ и УУ
Слева - статья затрат (БУ), справа статья управленческого учета (УУ). Важно при этом, чтобы в первом колонке статья затрат встречалась только один раз, иначе механизм мэппинга будет работать не корректно.
(Кстати, английское слово mapping переводится как отображение или соответствие, поэтому справочник в данном случае - это некое общее правило того, как статьи БУ находят свое отображение в статья УУ).
Рис.2.2. Плоская таблица: отчет о затратах (из "Оборотов счета 20")
Обратим внимание, что в 7-м столбце появилась графа "Статья УУ". Напротив каждой статьи затрат мы проставили статью управленческого учета. Это можно сделать вручную, но гораздо удобнее воспользоваться таким инструментом:
Рис.2.3. Плоская таблица: отчет о затратах (из "Оборотов счета 20")
В нижней части формы указаны наименования страниц: "Главная" - это плоская таблица, в которой содержатся данные о затратах (рис.2.2), "спр" - это справочник (рис.2.1).
В верхней части формы указаны номер столбцов. Так, в данном случае, если данные в столбцах 1 справочника и 3 главной страницы совпадают, то данные из 2-го столбца справочника копируются в 7-й столбец главной страницы.
В этой форме также мнржество дополнительных опций. Например, можно включить галочки "Признак #2" и "Признак #3", и тогда перенесение данных из столбца 2 справочника в столбец 7 главной страницы будет возможно, если справочник и главная страница будуь совпадать сразу по двум или даже трем реквизитам.
В результате такой несложной операции с помощью сводной таблицы можно построить целый ряд различных аналитических отчетов, в которых одним из разрезов будет фигурироватл аналитика "Стаьья УУ". Например, такой:
Рис.2.4. Отчет по затратам арматурного цеха
Сравнение мэппинга с ВПР()
Многие пользователи хорошо знакомы и пользуются функцией ВПР() в такого рода ситуациях. Однако функция ВПР() хорошо работает только на небольших объемах данны, в то время как данная форма отлично справляется с обработкой таблтц Excel, даже если у вас в справочнике, скажем, 5000 строк, а на гоавной странице - 300 000 строк. Попробуйте проверить, и вы убедитесь, что на таких объемах ВПР() дает сбои. Кроме того, функция ВПР() создает значительную нагрузку на Excel, вынуждая его проводить большие объесы калькуляций. Форма мэппинга позволяет избежать этого недостатка: она запускается один раз, действует несколько секунд (при больших объемах минут) и после этого никаких дополнительных нагрузок на файл Excel уже не создается.
Часть 3. Отображение данных из таблицы (Операция LIST)
В предыдущей части были рассмотрены виды связей (один-к-одному, один-ко-многим, многие-ко-многим), а также один класс 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
Public class Author {
public virtual int Id { get; set; }
//Имя-Фамилия
public virtual string Name { get; set; }
//Биография
public virtual string Biography { get; set; }
//Книжки
public virtual ISet
Класс Жанр
Public class Genre {
public virtual int Id { get; set; }
//Название жанра
public virtual string Name { get; set; }
//Английское название жанра
public virtual string EngName { get; set; }
//Книжки
public virtual ISet
Класс Мнение:
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 class Series {
public virtual int Id { get; set; }
public virtual string Name { get; set; } //Я создал IList, а не ISet, потому что кроме Book, Series больше ни с чем не связана, хотя можно сделать и ISet
public virtual IList
Небольшое объяснение
public virtual ISet
public virtual ISet
Почему ISet
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
Небольшое объяснение
- var books = session.QueryOver
() Select * From Book ; - .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 - .TransformUsing(Transformers.DistinctRootEntity) - Подобно выполнению скрипта SQL: SELECT distinct Book.Id... , (убирает дублирующие записи с одинаковыми id)
Виды объединений
.JoinAlias(p => p.Genres, () => genreAl, JoinType.LeftOuterJoin)
- LeftOuterJoin - выбирает все записи из левой таблицы (Book ), а затем присоединяет к ним записи правой таблицы (Genre ). Если не найдена соответствующая запись в правой таблицы, отображает её как Null
- RightOuterJoin действует в противоположность LEFT JOIN - выбирает все записи из правой таблицы (Genre ), а затем присоединяет к ним записи левой таблицы (Book )
- InnerJoin - выбирает только те записи из левой таблиц (Book ) у которой есть соответствующая запись из правой таблицы (Genre ), а затем присоединяет к ним записи из правой таблицы
Изменим представление следующим образом:
Представление index
@model IEnumerable @Html.ActionLink("Create New", "Create")
@foreach (var item in Model) {
@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)
@{string strSeries = item.Series != null ? item.Series.Name: null;}
@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
После запуска приложения, в БД Biblioteca появится следующая (пустая) таблица
Теги: Добавить метки
Слышали ли вы о mapping? В русской транскрипции это мэппинг, маппинг. Понятие имеет несколько значений, которые не связаны друг с другом. Рассмотрим каждое из них в контексте области, где они актуальны.
Что означает понятие в общем?
Мэппинг, маппинг, маппирование, мапирование - это определение соответствия информации между двумя разными семантиками как одного объекта, так и нескольких. Иными словами, так называется преобразование данных из одной формы в другую.
Что такое мэппинг? В общем значении термин достаточно широк - это может быть как скрупулезное преобразование одной последовательности элементов в иную, так и обычная конвертация валюты, файлов. Таким образом, все то, что скрывается под разбираемым термином, лучше всего выразить англоязычным понятием data mapping.
Примеры мэппинга
Разберем, что это - мэппинг, на следующих примерах:
- Составление документа соответствий бухгалтерских счетов из различных их планов. Например, российского, МСФО, управленческого учета и проч.
- Перевод кодов базы данных одной системы в другую. К примеру, нам надо преобразовать обозначения 0 и 1 в "нет" и "да".
- Перевод долларов в евро - это мэппинг в каком-то роде.
- Изменение формата изображения.png в.jpg, фильма из.avi в.mp4, проводимое в графическом, видеоредакторе, в каком-то роде будет относиться к предмету нашего разговора.
Разработка компьютерных игр
Мэппинг (от англ. map - "карта местности") также может выступать в значении дизайна уровней. Такое наименование имеет дисциплина в разработке видеоигр. Это прежде всего создание различной сложности уровней - проработка миссии игрока, дизайн локации, составление заданий и проч. Практически такая деятельность ведется в редакторе "левелов".
Технологии мэппинга здесь неоднородны - все зависит от бюджета разработчиков, характера, жанра создаваемой игры. Рассмотрим классический пример, чтобы иметь большее представление о понятии:
- Создание карты территории и ее разбиение на зоны - города, горный массив, подземные туннели, леса и проч.
- Определение регионов, связанных с какой-то специфической деятельностью игрока, - поле боя, магазин дополнительных атрибутов, добыча ресурсов, укрепления, место отдыха, доска почета и проч.
- Проработка нестатических объектов. Ими могут быть ключи, двери, секретные кнопки и ходы, исчезающие тайные проходы и проч.
- Определение важных локаций организаций - это точка восстановления, клады, сокровища, тайники с секретным оружием и проч.
- Установление места начала и финиша перемещений для каждого из игроков.
- Оживление карты рядом деталей: добавление таких элементов, как текстуры, звуки, аудиосопровождение, зрительные эффекты, иллюзии, анимации и проч.
- Вставка необходимых триггеров (механизмов, которые проверяют наличие какого-либо объекта в создаваемом игровом пространстве) и скриптов (сценариев, кратких алгоритмов действий).
- Создание определенных скриптов передвижения мобов (нестатичных объектов, персонажей): зоны, где они могут перемещаться, их взаимодействие, диалог с игроком и проч.
- Иногда включает создание кат-сцен - красивой заставки, мини-фильма, своеобразного трейлера игры или уровня, группы "левелов", которую геймер может только просмотреть, но никак не повлиять на то, что в ней происходит.
Видео-мэппинг
Что такое видео-мэппинг (3D-мэппинг)? Это удивительная технология, которая позволяет проецировать изображения, специально созданные фильмы на масштабные неровные поверхности, например, на фасады строений.
Уникальность этого в том, что оно позволяет "оживлять" дома, иные предметы интерьера тем, что придает им визуальную подвижность. А достигается все лишь установленными по определенному плану проекторами. "Магия" движущихся объемных изображений состоит в суперточном соответствии элементов, на которые отсвечивается картинка, и самой видеопроекции.
Хоть для многих из нас мэппинг - это достаточно новое направление, родился он еще в шестидесятых годах прошлого века. Его появлением мы обязаны Уолту Диснею и студии Disney. Тогда рабочим названием мэппинга были "затеняющие лампы", "пространство виртуальной реальности". Первым шоу считается аттракцион "Призрачное поместье" в Диснейленде. Для него были созданы искусственные отрубленные головы, на которые проецировалось изображение, "оживляющее" их.
Каким может быть видео-мэппинг?
В зависимости от объекта, на который отражается изображение, технология разделяется на несколько направлений:
- Архитектурное. Объемная проекция на сложный объект - фасад здания, мост, башню, а также на самолет, корабль и проч.
- Интерьерное. Создание интересных иллюзорных решений внутри помещения путем проецирования картинки на стены, потолок, пол.
- Для малых объектов. Используются как небольшие формы, так и элементы чего-то более масштабного. Например, колеса авто, торт, платье невесты и проч.
- Ландшафтное. Основой выступают лесные массивы, горы и прочие природные объекты.
- Интерактивное. Самое новое направление, отличное тем, что здесь героем становится человек. Технология оживляет предметы вокруг артиста, помогая ему создать незабываемое шоу.
Где применяется 3D-мэппинг?
Давайте посмотрим, где может оказаться актуальной такая технология:
- создание объемной на различных поверхностях;
- городские праздники, массовые мероприятия;
- крупные корпоративные события;
- открытия торговых центров, развлекательных комплексов;
- детские праздники;
- культурные, исторические, познавательные мероприятия.
Эффектнее всего такое шоу смотрится в темное время суток. Чтобы придать более поражающий эффект, организаторы сочетают его с подходящим объемным звуковым звучанием, живой музыкой, фейерверками.
Если вы хотите познакомиться с отзывами о технологии, то просто послушайте тех, кто хоть раз посещал московский "Круг света". С недавних пор каждый год осенью в столице проходит этот собирающий тысячи зрителей фестиваль. Дизайнеры из разных стран создают видеопроекции, которые показываются на фасаде Большого театра, главном павильоне ВДНХ, основном корпусе МГУ и пр.
Мэппинг - многозначное понятие. Это и сложная конвертация данных, и создание локаций в компьютерных играх, и шоу, основанное на проецировании изображений на масштабные и малые предметы.
В предыдущей части были рассмотрены виды связей (один-к-одному, один-ко-многим, многие-ко-многим), а также один класс 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
Public class Author {
public virtual int Id { get; set; }
//Имя-Фамилия
public virtual string Name { get; set; }
//Биография
public virtual string Biography { get; set; }
//Книжки
public virtual ISet
Класс Жанр
Public class Genre {
public virtual int Id { get; set; }
//Название жанра
public virtual string Name { get; set; }
//Английское название жанра
public virtual string EngName { get; set; }
//Книжки
public virtual ISet
Класс Мнение:
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 class Series {
public virtual int Id { get; set; }
public virtual string Name { get; set; } //Я создал IList, а не ISet, потому что кроме Book, Series больше ни с чем не связана, хотя можно сделать и ISet
public virtual IList
Небольшое объяснение
public virtual ISet
public virtual ISet
Почему ISet
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
Небольшое объяснение
- var books = session.QueryOver
() Select * From Book ; - .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 - .TransformUsing(Transformers.DistinctRootEntity) - Подобно выполнению скрипта SQL: SELECT distinct Book.Id... , (убирает дублирующие записи с одинаковыми id)
Виды объединений
.JoinAlias(p => p.Genres, () => genreAl, JoinType.LeftOuterJoin)
- LeftOuterJoin - выбирает все записи из левой таблицы (Book ), а затем присоединяет к ним записи правой таблицы (Genre ). Если не найдена соответствующая запись в правой таблицы, отображает её как Null
- RightOuterJoin действует в противоположность LEFT JOIN - выбирает все записи из правой таблицы (Genre ), а затем присоединяет к ним записи левой таблицы (Book )
- InnerJoin - выбирает только те записи из левой таблиц (Book ) у которой есть соответствующая запись из правой таблицы (Genre ), а затем присоединяет к ним записи из правой таблицы
Изменим представление следующим образом:
Представление index
@model IEnumerable @Html.ActionLink("Create New", "Create")
@foreach (var item in Model) {
@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)
@{string strSeries = item.Series != null ? item.Series.Name: null;}
@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
После запуска приложения, в БД Biblioteca появится следующая (пустая) таблица
Теги:
- asp.net mvc 4
- nhibernate
- sql server