• “Hello World” с использование NHibernate
  • Разбираемся с архитектурой
  • Написание и мэппинг (mapping) простой сущности (entity)
  • Конфигурирование NHibernate
  • Простые CRUD-операции

Для того, чтобы понять object/relational mapping, рассмотрим его на примере простого приложения, работающего с объектами БД.

1. Установка NHibernate

Скачать NHibernate можно с официального сайта в виде архива. В данном цикле статей, я буду использовать NHibernate 2.1.2.GA.

2. Проект в Visual Studio

Для начала создаем пустой бланк нового решения. Я назвал его “Hello NHibernate!” (неожиданно :) ).

Hello NHibernate

Добавим в решение проект консольное приложение с именем “HelloNHibernate”.

Hello NHibernate

В папке решения “Hello NHibernate!”, я рекомендую создать подпапку Libs для хранения библиотек, которые понадобятся в процессе работы. В этот каталог мы извлекаем и содержимое скачанного ранее архива NHibernate:

  • Required Bins
  • Required For LazyLoading
  • Tests

Теперь добавляем в References (Ссылки) NHibernate.dll. В классе Program.cs так же прописываем using NHibernate, using System.Reflection и NHibernate.Cfg.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
using System;
using NHibernate;
using System.Reflection;
using NHibernate.Cfg;

namespace HelloNHibernate
{
    class Program
    {
        static void Main(string[] args)
        {
        }
    }
}

3. Класс “Служащий” (Employee).

Цель приложения – работа с записями таблицы Employee, хранящей информацию о служащих фирмы. Следовательно, добавляем в проект новый класс и называем его соответственно таблице — “Employee”. Код класса:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
using System;

namespace HelloNHibernate
{
    class Employee
    {
        public int id;
        public string name;
        public Employee manager;
        public string SayHello()
        {
            return string.Format("'Hello World!', said {0}.", name);
        }
    }
}

Как видите, класс имеет три поля: идентификатор, имя служащего, ссылку на объект класса и метод, возвращающий строку типа “’Hello World!’, said Andrey”. Для читателей, имеющих опыт работы с NHibernate, оговорюсь заранее, свойства затрону позже, пока ограничимся только паблик переменными.

Теперь используем описанный выше класс в приложении:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
using System;
using NHibernate;
using System.Reflection;
using NHibernate.Cfg;
namespace HelloNHibernate
{
    class Program
    {
        static void Main(string[] args)
        {
            Employee anry = new Employee();
            anry.name = "Andrey Krisanov";
            Console.WriteLine(anry.SayHello());
            Console.ReadKey();
        }
    }
}
Hello NHibernate

4. База данных

Конечно же, БД! Именно она нужна нам для хранения и выполнения пр. операций с данными в нашем проекте. В качестве СУБД я использую Microsoft SQL Server 2008 Express Edition, однако NHibernate легко уживается и с другими. Приступим…

Запускаем Microsoft SQL Server Management Studio, соединяемся с сервером БД, открываем новое окно запросов и пишем код для создания новой базы:

1
2
CREATE DATABASE HelloNHibernate
GO

Выполняем его. Результат:
Hello NHibernate
Далее переключаемся на нашу БД и создаем таблицу Employee:

1
2
3
4
5
6
7
USE HelloNHibernate
GO
CREATE TABLE Employee (
    id int identity PRIMARY KEY,
    name varchar(50),
    manager int )
GO

Результат:
Hello NHibernate
В итоге, все необходимые каркасы для использования NHibernate мы создали.

5. Создание служащего и сохранение его в БД

Этот функционал описывают две функции: CreateEmployeeAndSaveToDatabase и OpenSession:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
static void CreateEmployeeAndSaveToDatabase()
{
    Employee andrey = new Employee();
    andrey.name = "Andrey Krisanov";

    using (ISession session = OpenSession())
    {
        using (ITransaction transaction = session.BeginTransaction())
        {
            session.Save(andrey);
            transaction.Commit();
        }
        Console.WriteLine("Saved Andrey to the databases");
    }
}

static ISessionFactory factory;

static ISession OpenSession()
{
    if (factory == null)
    {
        Configuration conf = new Configuration();
        conf.AddAssembly(Assembly.GetCallingAssembly());
        factory = conf.BuildSessionFactory();
    }
    return factory.OpenSession();
}

Функции реализуют интерфейсы NHibernate ISession, ITransaction. Так же имеется статическое поле factory, реализующее интерфейс ISessionFactory. Подробнее об этих интерфейсах расскажу позже. Пока достаточно знать, что SessionFactory создается один раз и используется на протяжении всей работы приложения, Session же можно создавать сколько угодно.

Если мы вызовем метод CreateEmployeeAndSaveToDatabase, NHibernate фактически выполнить SQL-запрос:

1
2
INSERT INTO Employees (name, manager)
VALUES ('Andrey Krisanov', NULL)

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

Итак, мы создали класс Служащий (Employee), добавили таблицу для его хранения в БД и написали некоторый код, для сохранения объекта с использованием NHibernate.

6. Загрузка служащих из базы данных

Получим список всех служащих, содержащихся в таблице и заставим сказать их “Привет мир!”.

Добавим код в Program.cs и не забудем подключить System.Collections.Generic для IList:

1
2
3
4
5
6
7
8
9
10
11
static void LoadEmployeesFromDatabase()
{
    using (ISession session = OpenSession())
    {
        IQuery query = session.CreateQuery("from Employee as emp order by emp.name asc");
        IList foundEmployees = query.List();
        Console.WriteLine("\n{0} employees found:", foundEmployees.Count);
        foreach (Employee employee in foundEmployees)
            Console.WriteLine(employee.SayHello());
    }
}

Литерал «from Employee as emp order by emp.name asc» – запрос NHibernate (HQL). Во время вызова query.List () он будет транслирован в SQL:

1
2
3
SELECT e.id, e.name, e.manager
FROM Employee e
ORDER BY e.name ASC

Есть и еще более простой способ получить все записи таблицы, но об этом снова позже :)

Подведем некоторые итоги. После прочтения вышеописанного материала у вас должно было сформироваться ощущение, что чего-то не хватает в структуре нашего проекта, какого-то связующего звена между Employee и NHibernate. Откуда берутся знания о классе для сохранения и извлечения соответствующих объектов? Отвечаю.

7. Создание файла мэппинга (mapping file)

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

Для IntelliSense закидываем в папку Microsoft Visual Studio\Xml\Schemas файлы схем NHibernate:

  • nhibernate-configuration.xsd
  • nhibernate-mapping.xsd

Затем добавляем в проект xml-файл, который называем Employee.hbm.xml, имя файла совпадает с именем класса + .hbm.xml.

Hello NHibernate

В свойствах Employee.hbm.xml в Build Action (Действие при построении) выбираем “Embedded Resource” (Внедренный ресурс). Не пропустите данный шаг, иначе NHibernate не сможет найти нужную мэппинг информацию!

Теперь открываем Employee.hbm.xml и прописываем в нем:

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" auto-import="true">
    <class name="HelloNHibernate.Employee, HelloNHibernate" lazy="false">
        <id name="id" access="field">
            <generator class="native" />
        </id>
        <property name="name" access="field" column="name"/>
        <many-to-one access="field" name="manager" column="manager" cascade="all"/>
    </class>
</hibernate-mapping>

При наборе кода, видим подсказки IntelliSense (не зря же мы копировали файлы схем в папку Студии).

Hello NHibernate

Итак, в файле мэппинга мы сообщили информацию о классе Employee, в какие столбцы таблицы будут записываться данные его полей. Как видите, все довольно просто.

Осталось сконфигурировать NHibernate под наш проект.

8. Конфигурирование приложения

Если вы ранее работали с БД в .NET (использовали DataSet, DataReader и пр.), то знаете о необходимости прописывать ConnectionString в файле web.config или app.config. Для NHibernate ситуация аналогичная:

  1. Добавляем в проект конфигурационный файл.
  2. Определяем настройки:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <configSections>
        <section name="hibernate-configuration"
            type="NHibernate.Cfg.ConfigurationSectionHandler, NHibernate" />
    </configSections>
    <hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
        <session-factory>
            <property name="proxyfactory.factory_class">NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle</property>
            <property name="connection.provider">
                NHibernate.Connection.DriverConnectionProvider
            </property>
            <property name="connection.driver_class">
                NHibernate.Driver.SqlClientDriver
            </property>
            <property name="connection.connection_string">
                Data Source=ANRY-NOTEBOOK\SQLEXPRESS;Initial Catalog=HelloNHibernate;Persist Security Info=True;User ID=test;Password=test
            </property>
            <property name="dialect">
                NHibernate.Dialect.MsSql2005Dialect
            </property>
            <property name="show_sql">
                false
            </property>
        </session-factory>
    </hibernate-configuration>
</configuration>

NHibernate очень гибок, и вариантов конфигурации ORM под ваши нужды существуем достаточно много. Обратите внимание, свойство “connection.connection_string” содержит строку подключения к БД, используемой в проекте. При необходимости, замените ее на актуальную для вашего сервера.

9. Обновление записи служащего

Перед тем, как запустить и проверить работу нашего приложения, добавим в него еще одну функцию, которая обновит запись обо мне и добавить новую:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
static void UpdateAndreyAndAssignNikolayAsManager()
{
    using (ISession session = OpenSession())
    {
        using (ITransaction transaction = session.BeginTransaction())
        {
            IQuery q = session.CreateQuery("from Employee where name = 'Andrey Krisanov'");
            Employee andrey = q.List()[0];
            andrey.name = "Andrey Anatolevich Krisanov";
            Employee nikolay = new Employee();
            nikolay.name = "Nikolay Evseev";
            andrey.manager = nikolay;
            transaction.Commit();
            Console.WriteLine("Updated Andrey and added Nikolay Evseev!");
        }
    }
}

При выполнении метода NHibernate переведет описанный выше код в SQL:

1
2
3
4
5
6
7
8
9
10
SELECT e.id, e.name, e.manager
FROM Employee e
WHERE e.id = 1
INSERT INTO Employees (name, manager)
VALUES ('Nikolay Evseev', NULL)
declare @newId int
SELECT @newId = scope_identity()
UPDATE Employees
SET name = 'Andrey Anatolevich Krisanov', manager = @newId
WHERE id = 1

ORM рулит! :)

10. Запуск программы

Ключевой момент данного топика – проверка работы написанного кода. Модифицируем метод Main () класса Program.cs:

1
2
3
4
5
6
7
8
static void Main(string[] args)
{
    CreateEmployeeAndSaveToDatabase();
    UpdateAndreyAndAssignNikolayAsManager();
    LoadEmployeesFromDatabase();
    Console.WriteLine("Press any key to exit...");
    Console.ReadKey();
}

Результат:

Hello NHibernate

Записи в таблице:

Hello NHibernate

P.S. Подключите к проекту следующие сборки:

Hello NHibernate

Исходник проекта

PodCodeРады сообщить о возобновлении записи нашего подкаста. Второй сезон открываем в пятницу (5 марта 2010) в 21:00 МСК.

Выпуск будет посвящен образованию и включать следующие темы:

  • Новый сезон подкаста: как и о чем?
  • Что дал Скаберону ВУЗ за 5 лет обучения?
  • Как мы учимся программировать?

P.S.> Ваши предложения оставляйте в комментариях.

P.S.2> Выпуск записан! Приятного прослушивания!

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

1. Допустим, метод вызывается при создании формы. Тогда определяем перегруженный конструктор второй формы:

1
2
3
4
5
6
private Form1 refForm;
public Form2(Form1 refForm)
{
    InitializeComponent();
    this.refForm = refForm;
}

Далее при вызове второй формы из первой передаем ссылку:

1
Form2 form = new Form2(this);

Готово. Осталось вызвать нужный метод. Но…

Что если Форма2 уже создана и показана пользователю и нужно сразу вызвать метод Формы1? Или возникает ситуация: Форма1 показывает Форму2, Форма2 показывает Форму3 и т.д., нужно вызвать из последней формы произвольный метод 1й формы? => Смотрим:

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

1
2
3
4
5
6
7
8
9
10
public static Form1 SelfRef
{
    get;
    set;
}

public Form1()
{
    SelfRef = this;
}

Наконец, в нужной форме (допустим Form3) выполняем нужный метод:

1
2
3
4
if(Form1.SelfRef != null)
{
    Form1.SelfRef.MyMethod();
}

P.S. По моему мнению, второй способ более удобен и гибок.

Постепенно погружаясь в веб-разработку, формирую список литературы, которая показалась мне интересной и нужной.

Первая книга в списке – книга-классика от O’Reilly:

Муссиано Ч., Кеннеди Б.
HTML и XHTML. Подробное руководство, 6е издание. – Пер. с англ. – СПб: Символ-Плюс, 2008. – 752 с., ил.

Оригинальное название – HTML & XHTML. The Definitive Guide. Sixth Edition.

HTML и XHTML. Подробное руководство, 6е издание

Эту книгу удобно иметь в электронном виде и при возникновении затруднительной ситуации или вопроса обращаться к ней. Лично у меня только электронный вариант, будут лишние средства, поставлю на полку и бумажный. Читать “HTML и XHTML. Подробное руководство” без практики скучно и нудно, особенно когда есть некоторые знания языка. Начинающим же разработчикам советую просмотреть книгу более менее основательно, понять основы, поэкспериментировать, применить полученные знания на практике и обращаться периодически как к справочнику.

Недавно я столкнулся с таким поисковым полем на поддерживаемом мной сайте:

image

Картинка с лупой была определена в поле как background и, соответственно, кнопкой не являлась. Пользователь мог только вводить запрос в поле и нажимать кнопку ENTER. Нужно было исправить эту ситуацию.

Сначала на странице шаблона сайта я написал следующий код:

1
2
3
4
5
6
<div id="search_box">
    <form id="search_form" action="/search/">
        <input type="text" name="q" id="s" value="Поиск" onclick="this.value=''"/>
        <input type="image" src="find_icon.png" width="20" height="20" id="go" alt="Search" />
    </form>
</div>

Был создан отдельный блок, содержащий саму форму поиска. Оговорюсь, что сайт работает на ASP.NET MVC, и action = “/search/” обрабатывает специальный контроллер. Форма состоит из текстового поля и кнопки-изображения. Причем, при помещении курсора в поле надпись “Поиск” удаляется сама (спасибо onclick="this.value=''").

Если просмотреть страницу в браузере, получим такой результат:

Поисковое поле с помощью CSS и фонового рисунка

Видно, что кнопка находится не в поле.

Не зря в каждом теге я расставил идентификаторы. CSS спешит на помощь :) . В файле стилей определяем стили для блока, поля поиска и кнопки:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* search */
#search_box {
    width: 192px;
    height: 24px;
    border: 1px solid #8c8c8c;
    margin: 10px 9px;
}
#search_box #s {
    float: left;
    padding: 0;
    margin: 6px 0 0 6px;
    border: 0;
    width: 159px;
    background: none;
}
#search_box #go {
    float: right;
    margin: 3px 4px 0 0;
}

Комментарии, думаю, излишни. Смотрим в браузере:

Поисковое поле с помощью CSS и фонового рисунка

Отлично! Кнопка кликабельна!

Скачать результат

P.S. > Данное решение работает во всех браузерах, в том числе и в IE6 (который так раздражает веб-разработчиков). Я понимаю, что можно написать (впрочем я и написал сначала) более красивый код с применением, например, jQuery, но IE6… Предлагайте ваши варианты в комментах, будет интересно сравнить.

В HTML (начиная с версии 4.0) есть два полезных и редко используемых тега — <ins> и <del>. Их еще называют тегами вставки и удаления. Теги позволяют выделять нужные части документа как обновленные и отмечать старый материал, подлежащий замене.

Теги <ins> и <del>. Описание

Пример использования:

1
2
3
4
5
6
7
8
9
10
11
12
<html>
<head>
    <title>Редакторская разметка</title>
</head>
<body>
    Статью о тегах вставки и удаления написал
    <ins datetime=2010-02-14 cite="http://podcode.ru">
    Андрей Крисанов
    </ins>
    <del>Вячеслав Скрипин</del>
</body>
</html>

Обратите внимание на атрибуты datetime и cite, которые я использую в теге. С помощью них указывается дата вставки (обновления) документа и источник, на основании которого сделана вставка. Аналогично можно поступить и с <del>.

Результат отображения в браузере:

HTML: Редакторская разметка


Страница 5 из 20« Первая...345671020...Последняя »

© 2009 PodCode – IT-заметки | Powered by Wordpress