13 октября 2008

А Вы как представляете себе Product?

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

Предположим есть у нас табличка в базе данных:
Product: id int — первичный ключ, name varchar(256), description text, is_visible bit.

Хотелось бы послушать Ваши мнения, как вы будете работать с данными, которые в ней хранятся. Предположим нужно вывести список продуктов (Уж поскольку я преимущественно работаю с Asp.net) на web-странице.

Но для начала я расскажу свой вариант и, надеюсь, он кому-нибудь да и пригодится.

Предположим, что данные из базы мы считали, но нужно их где-то хранить. Определённо сдесь следует использовать некий класс:
  1. public class Product
  2. {
  3. private Product(int id, string name, string description, bool isActive)
  4. {
  5. ID = id;
  6. Name = name;
  7. Description = description;
  8. IsActive = isActive;
  9. }
  10. int ID { get; private set; }
  11. string Name { get; set; }
  12. string Description { get; set; }
  13. bool IsActive { get; set; }
  14. }

Итак, есть класс, объекты которого будут ассоциироваться с записями в таблице Products, но нету возможности как-либо получить объекты, содержащие реальные данные.

Не проблемма, добавим статический метод, который будет возвращать, к примеру, все записи из таблицы:
  1. public static List<Product> GetAll()
  2. {
  3. //тут выполняются некоторые действия
  4. }

Так уж получилось, что я предпочёл использвать в качестве коллекции List. Но что делает даный метод?

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

Для каждого метода будем писать код подключения к базе данных? Конечно нет, просто скопируем, потом не заметим пары нюансов, а потом, думаю вы уже догадались…

Когда 10 месяцев назад я устроился работать программистом, то мне пришлось работать с уже готовым движком интернет магазина. Там методы получения коллекции объектов выглядели примерно так:
  1. public static ProductsCollection GetAll()
  2. {
  3. //Получаем таблицу
  4. DataTable table = DBClass.GetTable(query, parameters);
  5. //Проходим по всей таблице, занося данные в коллекцию
  6. foreach(DataRow row in table.Rows)
  7. {
  8. result.Add(GetProductFromRow(row));
  9. }
  10. return result;
  11. }

Сам метод GetAll не подключается в базе данных, это делает метод GetTable, нам остаётся лишь пройтись по таблице, перенося данные в коллекцию.

Удобно, не правдали? К сожалению нет, вернее удобно, но не так удобно, как хотелось бы.

Во-первых, происходит двойное копирование данных (БД => DataTable => Коллекция), во-вторых проход по таблице также придётся писать в каждом аналогичном методе, что является довольно рутиным занятием.

Чего бы хотелось? Примерно следующего:
  1. public static List<Product> GetAll()
  2. {
  3. return result;
  4. }

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

Поскольку в зависимости от объектов, с которыми этот метод будет работать, результатом будет коллекция именно объектов этого класса, то метод должен быть обобщенным.

Что нужно передавать методу? Во-первых комманду и её тип (sql-запрос или название хп), во-вторых, параметры. Ну и в-третьих, поскольку метод должен знать, как создавать объекты, некий делегат, который будет создавть объект.

Вот что у меня получилось:
  1. // Сообщение о последней возникшей ошибке
  2. public static string Error { get; private set; }
  3. // Строка подключения к базе данных
  4. private static readonly string connectionString = "..."
  5. // Первоначальный размер коллкции при получении нескольких объектов
  6. private const int itemsCount = 30;
  7. //Ну и сам метод
  8. public static List<T> GetList<T>(string commandText, CommandType commandType, DataReaderConstructor<T> dataReaderConstructor, params SqlParameter[] sqlParameters)
  9. where T : class
  10. {
  11. try
  12. {
  13. using (var connection = new SqlConnection(connectionString))
  14. {
  15. var command = new SqlCommand(commandText, connection) { CommandType = commandType };
  16. if (sqlParameters != null) command.Parameters.AddRange(sqlParameters);
  17. connection.Open();
  18. using (var reader = command.ExecuteReader())
  19. {
  20. if (reader == null) return null;
  21. var result = new List<T>(itemsCount);
  22. while (reader.Read())
  23. {
  24. result.Add(dataReaderConstructor(reader));
  25. }
  26. return result;
  27. }
  28. }
  29. }
  30. catch (Exception exeption)
  31. {
  32. Error = exeption.Message;
  33. return null;
  34. }
  35. }


Всё это находится в неком классе DBClass, за исключением объявления самого делегата, которое находится где-то неподалёку:
  1. public delegate T DataReaderConstructor<T>(IDataReader reader);

Теперь список продуктов можно достаточно просто получить скажем так:
  1. public static List<Product> GetAll()
  2. {
  3. return DBClass.GetList("SGetProducts", CommandType.StoredProcedure, Constructor)
  4. }

Перед этим объявив в классе Product метод:
  1. private static Product Constructor(IDataReader reader)
  2. {
  3. return new Product((int)reader[0], (string)reader[1], (string)reader[2], (bool)reader[3]);
  4. }


Но в начале статьи я поставил задачу отобразить список продуктов, а в неём, возможно, не используется описание, только ID и название.

Создать новый класс, где не будет описания по аналогии? Зачем? Ведь у нас есть анонимные типы и мы можем получить коллекцию идентификаторов и названий видимых продуктов используя анонимные типы:
  1. const string query = "Select ID, Name from Product where is_visible";
  2. var products = DBClass.GetList(query, CommandType.Text,
  3. reader => new
  4. {
  5. ID = (int) reader[0],
  6. Name = (string) reader[1]
  7. });
* This source code was highlighted with Source Code Highlighter.


Ну, собственно, вот это мой вариант. Жду критику, советы, предложения, ну и ещё немного критики.
Как Вы предпочитаете работать с данными?
Теги:работа с даннымиc sharp
Хабы: .NET
-3
896 1
Комментарии 14
Реклама
Лучшие публикации за сутки

Рекомендуем