27 декабря 2012 г.

Рекурсивный запрос на postgres

Актуальная версия этой статьи на моём новом сайте devmark.ru

Рассмотрим составление рекурсивных запросов на PostgreSQL для иерархических данных на примере следующей таблицы:
CREATE TABLE hierarchy_example
(
  id serial NOT NULL,
  name character varying(100),
  parent_id integer,
  CONSTRAINT id_pk PRIMARY KEY (id )
)
Заполним её данными:


parent_id содержит номер записи, которая является родительской по отношению к данной. Если parent_id = null, считаем, что это - корневой элемент иерархии.

Теперь составим запрос для прохода по этой иерархии, от элемента с именем subitem1 до root. На каждой итерации будем добавлять новую строку во временную таблицу temp1.

WITH RECURSIVE temp1 ( id, parent_id, name, path ) AS (
SELECT T1.id, T1.parent_id, T1.name, CAST (T1.name AS VARCHAR (50)) as PATH FROM hierarchy_example T1 WHERE T1.id = 4
union
select T2.id, T2.parent_id, T2.name, CAST ( temp1.PATH ||'->'|| T2.name AS VARCHAR(50)) FROM hierarchy_example T2 INNER JOIN temp1 ON (temp1.parent_id = T2.id))
select * from temp1

Рекурсивный запрос начинается со слов WITH RECURSIVE. Далее следует именованный набор полей временной таблицы temp1, в которую мы будем добавлять данные на каждой итерации.

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

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

Результат выполнения запроса:






Как видим, в столбце path последовательно отображается путь от subitem1 до root. Также обратите внимание, что в столбце name нет элемента item2 - он не входит в данную ветвь иерархии.

26 декабря 2012 г.

Полезные свойства System.getProperty

Актуальная версия этой статьи на моём новом сайте devmark.ru

Метод System.getProperties() возвращает список системных свойств, доступных для данной виртуальной машины. Свойство представляет из себя пару "ключ=значение". Среди полученных свойств всегда можно обнаружить следующие:

java.version - Версия Java
java.vendor - Строка, идентифицирующая изготовителя виртуальной машины Java
java.vendor.url - Адрес URL изготовителя виртуальной машины Java
java.home - Каталог, в который установлена система Java
java.class.version - Версия библиотеки классов Java
java.class.path - Путь к библиотеке классов Java
os.name - Название операционной системы
os.arch - Архитектура операционной системы
os.version - Версия операционной системы
file.separator - Разделитель файлов
path.separator - Разделитель пути
line.separator - Разделитель строк
user.name - Имя пользователя
user.home - Домашний каталог пользователя
user.dir - Текущий рабочий каталог пользователя (чаще всего тот каталог, где расположен исполняемый файл вашей программы).

Помимо указанных выше могут быть определены любые другие свойства. Например, свойства сервера приложений.

Получить отдельное значение по его ключу можно при помощи метода System.getProperty().

25 декабря 2012 г.

Основы анимации в WinForms

Проще всего двухмерную игру на .NET можно написать, используя стандартную технологию WinForms. Будем отображать графику на всей поверхности формы. Для этого сначала надо получить поверхность рисования GDI+ в виде объекта Graphics.

Graphics graphics = this.CreateGraphics();

this в данном случае представляет собой объект формы. Сам объект Graphics предоставляет богатый набор методов для рисования линий, кругов, прямоугольников и т.п. Причём вы можете задать, каким цветом рисовать фигуру, заливать ли её цветом всю или только границы фигуры. Также фигуру можно заполнить текстурой (повторяющимся изображением).

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

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

Однако в случае перерисовки по таймеру изображение начинает мерцать. Чтобы избежать мерцания изображения, нужно использовать BufferedGraphicsContext - графический буфер для двойной буферизации. Пример:

public Form1()
{
InitializeComponent();
Graphics graphics = this.CreateGraphics();            
bufferedGraphicsContext = new BufferedGraphicsContext();
bufferedGraphics = bufferedGraphicsContext.Allocate(graphics, new Rectangle(0, 0, this.Width, this.Height));
}

В конструкторе мы создаём буфер для всей поверхности рисования нашей формы. Далее по таймеру вызываем отрисовку изображения:

private void tmr_Tick(object sender, EventArgs e)
{
// здесь рисуем само изображение
bufferedGraphics.Graphics.Clear(Color.White);
engine.Draw(bufferedGraphics.Graphics, this.Size);
bufferedGraphics.Render();
}

Такая схема позволяет избежать мерцания при отрисовке изображения.