Данные, данные, данные… Постоянно приходится с ними работать и, конечно же, хотелось бы иметь для этого максимально комфортные условия.
Предположим есть у нас табличка в базе данных:
Product: id int — первичный ключ, name varchar(256), description text, is_visible bit.
Хотелось бы послушать Ваши мнения, как вы будете работать с данными, которые в ней хранятся. Предположим нужно вывести список продуктов (Уж поскольку я преимущественно работаю с Asp.net) на web-странице.
Но для начала я расскажу свой вариант и, надеюсь, он кому-нибудь да и пригодится.
Предположим, что данные из базы мы считали, но нужно их где-то хранить. Определённо сдесь следует использовать некий класс:
Итак, есть класс, объекты которого будут ассоциироваться с записями в таблице Products, но нету возможности как-либо получить объекты, содержащие реальные данные.
Не проблемма, добавим статический метод, который будет возвращать, к примеру, все записи из таблицы:
Так уж получилось, что я предпочёл использвать в качестве коллекции List. Но что делает даный метод?
Вариантов очень много. Самый очевидный — подключается к базе данных, выполняет запрос или хранимую процедуру, а затем помещает данные в коллекцию. Это не очень хороший способ. Вполне возможно, что придётся написать аналогичные методы, получающие только видимые элементы или элементы с непустым описанием.
Для каждого метода будем писать код подключения к базе данных? Конечно нет, просто скопируем, потом не заметим пары нюансов, а потом, думаю вы уже догадались…
Когда 10 месяцев назад я устроился работать программистом, то мне пришлось работать с уже готовым движком интернет магазина. Там методы получения коллекции объектов выглядели примерно так:
Сам метод GetAll не подключается в базе данных, это делает метод GetTable, нам остаётся лишь пройтись по таблице, перенося данные в коллекцию.
Удобно, не правдали? К сожалению нет, вернее удобно, но не так удобно, как хотелось бы.
Во-первых, происходит двойное копирование данных (БД => DataTable => Коллекция), во-вторых проход по таблице также придётся писать в каждом аналогичном методе, что является довольно рутиным занятием.
Чего бы хотелось? Примерно следующего:
И это вполне возможно. Просто нужен универсальный метод получения коллекции объектов.
Поскольку в зависимости от объектов, с которыми этот метод будет работать, результатом будет коллекция именно объектов этого класса, то метод должен быть обобщенным.
Что нужно передавать методу? Во-первых комманду и её тип (sql-запрос или название хп), во-вторых, параметры. Ну и в-третьих, поскольку метод должен знать, как создавать объекты, некий делегат, который будет создавть объект.
Вот что у меня получилось:
Всё это находится в неком классе DBClass, за исключением объявления самого делегата, которое находится где-то неподалёку:
Теперь список продуктов можно достаточно просто получить скажем так:
Перед этим объявив в классе Product метод:
Но в начале статьи я поставил задачу отобразить список продуктов, а в неём, возможно, не используется описание, только ID и название.
Создать новый класс, где не будет описания по аналогии? Зачем? Ведь у нас есть анонимные типы и мы можем получить коллекцию идентификаторов и названий видимых продуктов используя анонимные типы:
Ну, собственно, вот это мой вариант. Жду критику, советы, предложения, ну и ещё немного критики.
Как Вы предпочитаете работать с данными?
Предположим есть у нас табличка в базе данных:
Product: id int — первичный ключ, name varchar(256), description text, is_visible bit.
Хотелось бы послушать Ваши мнения, как вы будете работать с данными, которые в ней хранятся. Предположим нужно вывести список продуктов (Уж поскольку я преимущественно работаю с Asp.net) на web-странице.
Но для начала я расскажу свой вариант и, надеюсь, он кому-нибудь да и пригодится.
Предположим, что данные из базы мы считали, но нужно их где-то хранить. Определённо сдесь следует использовать некий класс:
- public class Product
- {
- private Product(int id, string name, string description, bool isActive)
- {
- ID = id;
- Name = name;
- Description = description;
- IsActive = isActive;
- }
-
- int ID { get; private set; }
- string Name { get; set; }
- string Description { get; set; }
- bool IsActive { get; set; }
- }
Итак, есть класс, объекты которого будут ассоциироваться с записями в таблице Products, но нету возможности как-либо получить объекты, содержащие реальные данные.
Не проблемма, добавим статический метод, который будет возвращать, к примеру, все записи из таблицы:
- public static List<Product> GetAll()
- {
- //тут выполняются некоторые действия
- }
Так уж получилось, что я предпочёл использвать в качестве коллекции List. Но что делает даный метод?
Вариантов очень много. Самый очевидный — подключается к базе данных, выполняет запрос или хранимую процедуру, а затем помещает данные в коллекцию. Это не очень хороший способ. Вполне возможно, что придётся написать аналогичные методы, получающие только видимые элементы или элементы с непустым описанием.
Для каждого метода будем писать код подключения к базе данных? Конечно нет, просто скопируем, потом не заметим пары нюансов, а потом, думаю вы уже догадались…
Когда 10 месяцев назад я устроился работать программистом, то мне пришлось работать с уже готовым движком интернет магазина. Там методы получения коллекции объектов выглядели примерно так:
- public static ProductsCollection GetAll()
- {
- //Получаем таблицу
- DataTable table = DBClass.GetTable(query, parameters);
- //Проходим по всей таблице, занося данные в коллекцию
- foreach(DataRow row in table.Rows)
- {
- result.Add(GetProductFromRow(row));
- }
- return result;
- }
Сам метод GetAll не подключается в базе данных, это делает метод GetTable, нам остаётся лишь пройтись по таблице, перенося данные в коллекцию.
Удобно, не правдали? К сожалению нет, вернее удобно, но не так удобно, как хотелось бы.
Во-первых, происходит двойное копирование данных (БД => DataTable => Коллекция), во-вторых проход по таблице также придётся писать в каждом аналогичном методе, что является довольно рутиным занятием.
Чего бы хотелось? Примерно следующего:
- public static List<Product> GetAll()
- {
- return result;
- }
И это вполне возможно. Просто нужен универсальный метод получения коллекции объектов.
Поскольку в зависимости от объектов, с которыми этот метод будет работать, результатом будет коллекция именно объектов этого класса, то метод должен быть обобщенным.
Что нужно передавать методу? Во-первых комманду и её тип (sql-запрос или название хп), во-вторых, параметры. Ну и в-третьих, поскольку метод должен знать, как создавать объекты, некий делегат, который будет создавть объект.
Вот что у меня получилось:
- // Сообщение о последней возникшей ошибке
- public static string Error { get; private set; }
- // Строка подключения к базе данных
- private static readonly string connectionString = "..."
- // Первоначальный размер коллкции при получении нескольких объектов
- private const int itemsCount = 30;
- //Ну и сам метод
- public static List<T> GetList<T>(string commandText, CommandType commandType, DataReaderConstructor<T> dataReaderConstructor, params SqlParameter[] sqlParameters)
- where T : class
- {
- try
- {
- using (var connection = new SqlConnection(connectionString))
- {
- var command = new SqlCommand(commandText, connection) { CommandType = commandType };
- if (sqlParameters != null) command.Parameters.AddRange(sqlParameters);
- connection.Open();
- using (var reader = command.ExecuteReader())
- {
- if (reader == null) return null;
- var result = new List<T>(itemsCount);
- while (reader.Read())
- {
- result.Add(dataReaderConstructor(reader));
- }
- return result;
- }
- }
- }
- catch (Exception exeption)
- {
- Error = exeption.Message;
- return null;
- }
- }
Всё это находится в неком классе DBClass, за исключением объявления самого делегата, которое находится где-то неподалёку:
- public delegate T DataReaderConstructor<T>(IDataReader reader);
Теперь список продуктов можно достаточно просто получить скажем так:
- public static List<Product> GetAll()
- {
- return DBClass.GetList("SGetProducts", CommandType.StoredProcedure, Constructor)
- }
Перед этим объявив в классе Product метод:
- private static Product Constructor(IDataReader reader)
- {
- return new Product((int)reader[0], (string)reader[1], (string)reader[2], (bool)reader[3]);
- }
Но в начале статьи я поставил задачу отобразить список продуктов, а в неём, возможно, не используется описание, только ID и название.
Создать новый класс, где не будет описания по аналогии? Зачем? Ведь у нас есть анонимные типы и мы можем получить коллекцию идентификаторов и названий видимых продуктов используя анонимные типы:
- const string query = "Select ID, Name from Product where is_visible";
- var products = DBClass.GetList(query, CommandType.Text,
- reader => new
- {
- ID = (int) reader[0],
- Name = (string) reader[1]
- });
* This source code was highlighted with Source Code Highlighter.
Ну, собственно, вот это мой вариант. Жду критику, советы, предложения, ну и ещё немного критики.
Как Вы предпочитаете работать с данными?