Лучшие практики баз данных для начинающих
Итак, я довольно новый программист, работающий по направлению на степень бакалавра Comp Sci с очень небольшим количеством опыта работы. При поиске заданий на стажировку для моей программы я заметил, что то, что я слышал от нескольких профессоров - "работа с базами данных составляет 90% от всех современных заданий в области компьютерных наук" - похоже, что это действительно так. Тем не менее, моя программа на самом деле не имеет курсов с базами данных до 3-го года, поэтому я стараюсь, по крайней мере, научиться чему-то самому себе в среднем.
Я видел очень мало на SO и в интернете вообще для кого-то вроде меня. Кажется, что есть тонны учебников по механике, как читать и писать данные в базе данных, но мало о соответствующих передовых методах. Чтобы продемонстрировать, о чем я говорю, и чтобы помочь решить мой фактический вопрос, вот что можно легко найти в Интернете:
public static void Main ()
{
using (var conn = new OdbcConnection())
{
var command = new OdbcCommand();
command.Connection = conn;
command.CommandText = "SELECT * FROM Customer WHERE id = 1";
var dbAdapter = new OdbcDataAdapter();
dbAdapter.SelectCommand = command;
var results = new DataTable();
dbAdapter.Fill(results);
}
// then you would do something like
string customerName = (string) results.Rows[0]["name"];
}
И так далее. Это довольно просто понять, но, очевидно, полный проблем. Я начал с кода вроде этого и быстро начал говорить такие вещи, как "Ну, кажется, глупо иметь SQL везде, я должен положить все это в файл констант". И тогда я понял, что глупо иметь те же самые строки кода повсюду и просто помещать все это с объектами подключения и т.д. Внутри метода:
public DataTable GetTableFromDB (string sql)
{
// code similar to first sample
}
string getCustomerSql = String.Format(Constants.SelectAllFromCustomer, customerId);
DataTable customer = GetTableFromDB(getCustomerSql);
string customerName = (string) customer.Rows[0]["name"];
Это казалось большим улучшением. Теперь это супер-легко, скажем, перейти от OdbcConnection к SQLiteConnection. Но эта последняя строка, доступ к данным, все еще казалась неудобной; и по-прежнему больно менять имя поля (например, переходить от "name" в "CustName" или что-то еще). Я начал читать о с использованием типизированных наборов данных или настраиваемых бизнес-объектов. Я все еще смущен всей терминологией, но решил посмотреть в нее в любом случае. Я полагаю, что глупо полагаться на блестящий Мастер базы данных, чтобы сделать все это для меня (как в связанных статьях), прежде чем я действительно узнаю, что происходит, и почему. Поэтому я сам взял в него удар и начал получать такие вещи, как:
public class Customer
{
public string Name {get; set;}
public int Id {get; set;}
public void Populate ()
{
string getCustomerSql = String.Format(Constants.SelectAllFromCustomer, this.Id);
DataTable customer = GetTableFromDB(getCustomerSql);
this.Name = (string) customer.Rows[0]["name"];
}
public static IEnumerable<Customer> GetAll()
{
foreach ( ... ) {
// blah blah
yield return customer;
}
}
}
чтобы скрыть уродливое содержимое таблицы и обеспечить сильную типизацию, позволяя внешнему коду просто делать что-то вроде
var customer = new Customer(custId);
customer.Populate();
string customerName = customer.Name;
что действительно приятно. И если таблица Customer изменяется, изменения в коде должны произойти только в одном месте: внутри класса Customer
.
Итак, в конце всего этого бессвязного, мой вопрос таков. Произошла ли моя медленная эволюция кода базы данных в правильном направлении? И куда я иду дальше? Этот стиль хорошо подходит для небольших баз данных, но когда есть множество разных таблиц, выписывать все эти классы для каждого из них будет больно. Я слышал о программном обеспечении, которое может генерировать этот тип кода для вас, но я все еще смущен DAR/ORM/LINQ2SQL/etc жаргоном, и эти огромные программные продукты являются подавляющими. Я ищу какие-то хорошие, не подавляюще сложные ресурсы, которые могут указывать мне в правильном направлении. Все, что я могу найти на эту тему, - это сложные статьи, которые проходят по моей голове, или статьи, которые просто показывают вам, как использовать мастеров point-and-click в Visual Studio и т.д. Также обратите внимание, что я ищу информацию о работе с базами данных в коде, а не информацию о дизайне/нормализации базы данных... там есть много хорошего материала.
Спасибо, что прочитали эту гигантскую стену текста.
Ответы
Ответ 1
Очень хороший вопрос, и вы, безусловно, на правильном пути!
Будучи самим инженером-программистом, базы данных и способы написания кода для взаимодействия с базами данных также не были большой частью моей университетской степени, и я уверен, что я несу ответственность за весь код базы данных на работе.
Вот мой опыт, используя устаревшие технологии с начала 90-х годов по одному проекту и современные технологии с С# и WPF на другом.
Я сделаю все возможное, чтобы объяснить терминологию, пока я иду, но я, конечно, еще не эксперт.
Таблицы, объекты и сопоставления Oh My!
База данных содержит таблицы, но что на самом деле? Это просто плоские данные, связанные с другими плоскими данными, и если вы погрузитесь и начнете захватывать вещи, они скоро станут беспорядочными! Строки будут повсюду, повторяются операторы SQL, дважды загружаются записи и т.д. Поэтому обычно рекомендуется представлять каждую запись таблицы (или коллекцию записей таблиц в зависимости от их отношений) как единый объект, обычно называемый в качестве модели. Это помогает инкапсулировать данные и предоставлять функции для поддержания и обновления состояния.
В вашей публикации ваш класс Customer будет действовать как Модель! Итак, вы уже поняли эту выгоду.
Теперь существует множество инструментов/фреймворков (LINQ2SQL, dotConnect, Mindscape LightSpeed), которые будут писать для вас весь ваш код модели. В конечном итоге они сопоставляют объекты с реляционными таблицами или сопоставлением O/R, поскольку они ссылаются на него.
Как и ожидалось, при изменении вашей базы данных ваши сопоставления O/R. Как и вы, затронутый, если ваш Клиент меняет, вы должны исправить его в одном месте, опять же, почему мы помещаем вещи в классы. В случае с моим старым проектом обновление моделей потребляло много времени, потому что их было так много, в то время как в моем новом проекте это несколько кликов, но в конечном итоге результат тот же.
Кто должен знать что?
В моих двух проектах было два разных способа взаимодействия объектов с их таблицами.
В некоторых лагерях модели должны знать все о своих таблицах, о том, как сохранить себя, иметь прямой общий доступ к соединению/сеансу и сами выполнять действия типа Customer.Delete()
и Customer.Save()
.
Другие лагеря, ставят чтение, письмо, удаление, логику в управляющем классе. Например, MySessionManager.Save( myCustomer )
. Преимущество этой методологии заключается в том, что она позволяет легко осуществлять отслеживание изменений объектов и обеспечивать, чтобы все объекты ссылались на одну и ту же базовую запись таблицы. Однако его реализация более сложна, чем метод упоминания ранее локализованной логики класса/таблицы.
Заключение
Вы на правильном пути, и, на мой взгляд, взаимодействие с базами данных чрезвычайно полезно. Я помню, как моя голова вращалась, когда я впервые начал заниматься исследованиями.
Я бы порекомендовал немного поэкспериментировать, запустил небольшой проект, возможно, простую систему выставления счетов, и попробуйте написать модели самостоятельно. После этого попробуйте еще один небольшой проект и попробуйте использовать инструмент отображения O/R базы данных и увидите разницу.
Ответ 2
Ваша эволюция определенно в правильном направлении. Еще несколько вещей, которые следует учитывать:
Ответ 3
Мой совет, если вы хотите узнать о базах данных, первый шаг - забыть о языке программирования, затем забыть о том, какую базу данных вы используете и изучать SQL. Конечно, есть много различий между mySQL, MS SQLserver и Oracle, но есть так много, что одно и то же.
Узнайте о объединениях, выберите в качестве форматов даты, нормализации. Узнайте, что происходит, когда у вас есть миллионы и миллионы записей, и все начинает замедляться, а затем научитесь исправлять его.
Создайте тестовый проект, связанный с чем-то, что вас интересует, например, магазин велосипедов. Посмотрите, что произойдет, когда вы добавите несколько миллионов продуктов и несколько миллионов клиентов и подумайте о том, как эти данные должны быть связаны.
Используйте настольное приложение для запуска запросов в локальной базе данных (продолжение pro, mysql workbench и т.д.), так как это намного быстрее, чем загрузка исходного кода на сервер. И получайте удовольствие от этого!
Ответ 4
ИМХО, вы определенно идете в правильном направлении, чтобы действительно приятно работать с поддерживаемым кодом! Однако я не уверен, что подход будет масштабироваться до реального приложения. Несколько соображений, которые могут быть полезны
- В то время как код, который вы пишете, будет действительно приятным для работы и действительно поддерживаемым, он включает в себя много работы вверх, это часть причины, по которой мастера так популярны. Они не самые приятные вещи для работы, но сэкономить много времени.
- Запрос из базы данных - это только начало; Другая причина для использования типизированных наборов данных и мастеров в целом заключается в том, что в большинстве приложений пользователи на какой-то стадии собираются отредактировать вашу информацию и отправить ее для обновления. Одиночные записи прекрасны, но что делать, если ваши данные лучше всего представлены стандартизованным способом с иерархией таблиц 4 в глубину? Написание кода для автоматического создания инструкций обновления/вставки/удаления вручную для всех вызовов, которые являются адскими, поэтому инструменты - единственный путь вперед. напечатанные DataSets будут генерировать весь код для выполнения этих обновлений для вас и иметь очень мощные функции для обработки отключенных (например, на стороне клиента) обновлений/откатов последних изменений.
- Что говорили последние ребята о SQL-инъекции (которая является серьезным событием в индустрии) и защищая себя, используя DBCommand объект и добавление DbParameters.
В целом существует действительно большая проблема при переходе от кода к базам данных, называемом несоответствие импеданса. Преодоление разрыва очень сложно, и поэтому большинство отраслей промышленности полагаются на инструменты для тяжелого подъема. Моим советом было бы попытаться освоить волшебников - потому что в то время как прохождение через волшебник не является испытанием по навыкам, изучение всех их недостатков/ошибок и их различных обходных решений - действительно полезный навык в отрасли и позволит вам перейти к более продвинутым сценарии в управлении данными быстрее (например, отключенное обновление иерархии таблиц с 4 глубинами, о которой я упоминал).
Ответ 5
Если вы немного боитесь таких вещей, как Linq to SQL и Entity Framework, вы можете шагнуть на полпути между ними и исследовать что-то вроде iBATIS.NET. Это просто инструмент для преобразования данных, который принимает некоторые из недостатков управления подключением к базе данных и сопоставляет ваши результирующие наборы с пользовательскими объектами домена.
Вам все равно придется писать все классы объектов и SQL, но он отображает все ваши данные в классы для вас, используя отражение, и вам не нужно беспокоиться обо всех базовых связях (вы можете легко написать инструмент для создания ваших классов). Когда вы работаете с iBATIS (предположим, что вам может быть интересно), ваш код начнет выглядеть следующим образом:
var customer = Helpers.Customers.SelectByCustomerID(1);
Эта функция SelectByCustomerID
существует внутри преобразователя Customers
, определение которой может выглядеть так:
public Customer SelectByCustomerID(int id)
{
Return Mapper.QueryForObject<Customer>("Customers.SelectByID", id);
}
"Customers.SelectByID" сопоставляется с определением инструкции XML, где "Клиенты" - это пространство имен, а "SelectByID" - это идентификатор карты, содержащей ваш SQL:
<statements>
<select id="SelectByID" parameterClass="int" resultClass="Customer">
SELECT * FROM Customers WHERE ID = #value#
</select>
</statements>
Или, когда вы хотите изменить клиента, вы можете делать такие вещи, как:
customer.FirstName = "George"
customer.LastName = "Costanza"
Helpers.Customers.Update(customer);
LINQ to SQL и Entity Framework становятся более привлекательными, создавая SQL для вас автоматически. Мне нравится iBATIS, потому что у меня все еще есть полный контроль над SQL и мои объекты домена.
Проверьте iBATIS (теперь перенесен в Google под именем MyBatis.NET). Еще один отличный пакет - NHibernate, что на несколько шагов впереди iBATIS и ближе к полному ORM.
Ответ 6
Визуальная страница базы данных с помощью combobox и datagrid
пространство имен
TestDatabase.Model
{ База данных классов
{
private MySqlConnection connecting;
private MySqlDataAdapter adapter;
public Database()
{
connecting = new MySqlConnection("server=;uid=;pwd=;database=;");
connecting.Open();
}
public DataTable GetTable(string tableName)
{
adapter = new MySqlDataAdapter("SELECT * FROM "+ tableName, connecting);
DataSet ds = new DataSet();
adapter.Fill(ds);
adapter.UpdateCommand = new MySqlCommandBuilder(adapter).GetUpdateCommand();
adapter.DeleteCommand = new MySqlCommandBuilder(adapter).GetDeleteCommand();
ds.Tables[0].RowChanged += new DataRowChangeEventHandler(Rowchanged);
ds.Tables[0].RowDeleted += new DataRowChangeEventHandler(Rowchanged);
return ds.Tables[0];
}
public void Rowchanged(object sender, DataRowChangeEventArgs args)
{
adapter.Update(sender as DataTable);
}
}
}
Ответ 7
VMV DATABSE
namespace TestDatabase.ViewModel
{
class MainViewModel : INotifyPropertyChanged
{
private Model.Database database;
private DataTable table;
public string[] options;
public string selected;
public DataTable Table
{
get { return table; }
set { table = value;
ChangeProperty("Table"); }
}
public string[] Options
{
get { return options; }
}
public string Selected
{
get { return selected; }
set
{ selected = value;
Table = database.GetTable(value);
}
}
public MainViewModel()
{
database = new Model.Database();
options = new string[] { "" }; // names of tables
}
public event PropertyChangedEventHandler PropertyChanged;
private void ChangeProperty(string name)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
}
}