Привет всем хабраюзерам, решил написать первую свою статью, которая, продолжает серию очерков про взаимодействие с БД. Так случилось что подвернулся небольшой вэб-проект для реализации. В качестве платформы был выбран ASP.NET MVC + ExtJS но вот решение для ORM сходу не нашлось. Проблема заключалась в том что привлекать большое промышленное ORM решение типа NHibernate или Entity Framework не хотелось, так как проект будет иметь от силы два-три десятка хранимых процедур. Одновременно с этим использовать обвертку от Microsoft DAAB тоже не получается, т.к. в MVC фреймворке модели являются по сути копиями таблиц БД (ну просто для упрощения будем так считать) в результате Reader-ы, DataSet-ы и DataTable-ы нам мало чем могут помочь. Возможно хорошим решением было бы использовать LinqToSql, но мне очень не нравиться когда запросы написаны не на SQL а на C#, я твердо убеждён что общение между приложением и БД должно происходить только посредством хранимых процедур и функций. Другими словами нам нужен маппинг класа на result set хранимой процедуры и простота его использования, что бы просто вызвать хелпер-метод и он, используя рефлексию, вернул коллекцию экземпляров наполненными данными из процедуры. Думаю суть проблемы я изложил достаточно понятно итак приступим к реализации.
Для начала объявим наш класс который будем наполнять данными, само собой, что он будет полностью копировать поля которые возвращает хранимая процедура:
А вот и хелпер-метод для маппинга:
Метод реализован как generic method который возвращает коллекцию System.Collections.Generic.List  наполненную экземплярами нашего класса, для простоты реализации в нем опущена передача параметров в процедуру и реализована работа всего с 4 типами данных Int32, Int16, String и DateTime, но вы с легкость сможете его расширить и дополнить функционально.
Ну и конечно же пример использования:
Ну вот собственно и все что я хотел рассказать в своей статье, с нетерпением жду замечаний и конструктивной критики.
Для начала объявим наш класс который будем наполнять данными, само собой, что он будет полностью копировать поля которые возвращает хранимая процедура:
public class Book
{
public int ID { get; set; }
public string Title { get; set; }
public string Author { get; set; }
public DateTime PublicationDate { get; set; }
}
* This source code was highlighted with Source Code Highlighter.
А вот и хелпер-метод для маппинга:
public static List<T> GetSpResultset<T>(string spName)
{
List<T> list = new List<T>();
SqlConnection connection = new SqlConnection("строка соединения");
connection.Open();
using (SqlCommand command = new SqlCommand(spName, connection))
{
command.CommandType = CommandType.StoredProcedure;
using (IDataReader reader = command.ExecuteReader(CommandBehavior.CloseConnection))
{
PropertyInfo[] fields = typeof(T).GetProperties();
while (reader.Read())
{
T record = Activator.CreateInstance<T>();
foreach (PropertyInfo pi in fields)
{
if (pi.PropertyType.Name == typeof(Int32).Name)
{
if (pi.CanWrite)
{
int value = reader.GetInt32(reader.GetOrdinal(pi.Name));
pi.SetValue(record, value, null);
}
}
else if (pi.PropertyType.Name == typeof(Int16).Name)
{
if (pi.CanWrite)
{
short value = Convert.ToInt16(reader.GetValue(reader.GetOrdinal(pi.Name)));
pi.SetValue(record, value, null);
}
}
else if (pi.PropertyType.Name == typeof(String).Name)
{
if (pi.CanWrite)
{
string value = reader.GetString(reader.GetOrdinal(pi.Name));
pi.SetValue(record, value, null);
}
}
else if (pi.PropertyType.Name == typeof(DateTime).Name)
{
if (pi.CanWrite)
{
DateTime value = reader.GetDateTime(reader.GetOrdinal(pi.Name));
pi.SetValue(record, value, null);
}
}
}
list.Add(record);
}
}
}
return list;
}
* This source code was highlighted with Source Code Highlighter.
Метод реализован как generic method который возвращает коллекцию System.Collections.Generic.List  наполненную экземплярами нашего класса, для простоты реализации в нем опущена передача параметров в процедуру и реализована работа всего с 4 типами данных Int32, Int16, String и DateTime, но вы с легкость сможете его расширить и дополнить функционально.
Ну и конечно же пример использования:
List<Book> books = GetSpResultset<Book>("sp_GetBooks");
* This source code was highlighted with Source Code Highlighter.
Ну вот собственно и все что я хотел рассказать в своей статье, с нетерпением жду замечаний и конструктивной критики.