Моделирование таблиц базы данных в классы - PullRequest
0 голосов
/ 06 июня 2009

Я разрабатываю личный проект, который в основном базируется на базе данных. Я пытаюсь придумать хороший дизайн для обработки взаимодействия с базой данных, и мне бы хотелось, чтобы мнения опытных специалистов здесь, в StackOverflow.

Является ли следующий хороший дизайн или есть более стандартный способ обработки связи с базой данных?

EDIT
В основном я искал отклики о том, было ли обычным делить детали соединения на их собственный базовый класс с подклассами для логических единиц / классов.
С этой целью я изменил код ниже, чтобы добавить метод поиска, чтобы дополнить метод вставки в исходном вопросе. Я также изменил его, чтобы показать, что он принимает / возвращает (в зависимости от метода) бизнес-объекты.
Например, в этом примере мы используем класс Employee во всем приложении, но у нас есть класс EmployeeDb (унаследованный от базы данных), который обрабатывает его постоянство в / из базы данных.

Мне это нравится, потому что он хранит детали реализации хранилища вне бизнес-объектов, но не нравится, потому что он сильно связывает классы Employee и EmployeeDB.

</p> <pre><code>// Abstract Base Class to handle specifics of the database connection abstract class Database : IDisposable { protected OleDbConnection m_Conn; public bool Open() { // Open a connection to the database } public void Dispose() { if (m_Conn != null) { m_Conn.Dispose(); } } } // Specific classes for each table, with methods for CRUD functions class EmployeeDB : Database { public bool AddTestData(Employee emp) { // Construct SQL to add Employee class members to the DB, breaking // them out into their component tables as needed } public List<Employee> GetEmployeeByProject(string project) { // Retrieve recordset of all employees on the project, // breaking them out into instances of the Employee class // Add each new Employee object to a list, and return the list // to the caller. } } // Specific classes for each table (or logical unit, since obviously // most of the time we'll need to join a few tables to get what // we want), with methods for CRUD functions void AddSomethingToTheDatabase() { using (TestDataDB td = new TestDataDB()) { td.Open(Application.StartupPath); string NewID = td.AddTestData(txtAddMe.Text); } }

Ответы [ 3 ]

7 голосов
/ 06 июня 2009

Вы уверены, что не хотите попробовать Object Relational Mapper ?

Может быть Linq to SQL или nHibernate ?

1 голос
/ 06 июня 2009

Есть много способов сделать это, и подавляющее большинство ОО не согласятся с моим.

Я предлагаю вам использовать более реляционный подход и вместо классов для таблиц использовать классы для отношений. В реляционной теории результатом запроса является отношение, аналогичное отношениям, которые использовались в запросе; на самом деле вы никогда не видите ничего, кроме результатов запросов, поскольку даже для получения содержимого таблицы вам нужно SELECT * FROM x, которая применяет к ней функцию идентификации.

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

0 голосов
/ 06 июня 2009

Я бы спонтанно хотел немного отключить зависимость базы данных от объектов. Вы могли бы начать с создания интерфейса, который определяет методы хранения для вашего объекта TestData (в моем примере есть только метод Add, но это, конечно, можно расширить):

public interface ITestDataRepository
{
    void Add(TestData data);
}

Следующим шагом является создание класса TestData. Одной из функций этого класса может быть принятие ITestDataRepository в качестве параметра в конструкторе и предоставление метода Add:

public class TestData
{
    public TestData(ITestDataRepository repository)
    {
        Repository = repository;
    }

    public ITestDataRepository Repository { get; private set; }

    public string SomeData { get; set; }

    public void Add()
    {
        if (Repository != null)
        {
            Repository.Add(this);
        }
    }
}

Последнее, что нужно сделать, - реализовать механизм данных, который вы хотите использовать. В данном случае это OleDb, но это может быть также Xml, SqlServer или любая другая форма хранения данных:

public class DbTestDataRepository : ITestDataRepository
{
    const string InsertionQuery = @"INSERT INTO TEST (TESTDATA) VALUES (?)";

    public void Add(TestData data)
    {

        using (OleDbConnection conn = DbUtil.GetConnection())
        using (OleDbCommand command = new OleDbCommand(InsertionQuery, conn))
        {
            command.Parameters.Add("@p1", OleDbType.BSTR).Value = data.SomeData;

            using (OleDbDataReader reader = command.ExecuteReader())
            {
                // perhaps log something?
            }
        }
    }

}

Приведенный выше дизайн предоставляет несколько различных преимуществ по сравнению с дизайном в вашем вопросе:

  • Нет жесткой связи между вашей объектной моделью и конкретной реализацией хранилища; например, вы можете изменить механизм хранения без изменения объекта TestData.
  • Это проверяемое; поскольку единственное требование к механизму хранения данных заключается в том, что он реализует интерфейс хранилища, хранилище данных можно легко смоделировать, что облегчает модульное тестирование.
  • В этом конкретном коде базы данных объект соединения живет только в течение очень короткого момента, который обычно является рекомендуемым способом сделать это (метод DbUtil.GetConnection - это то, что я «изобрел»; его нет, но обычно нравится централизовать код для настройки соединения, поэтому я не умножаю его на весь код).

Это всего лишь несколько быстрых идей (например, я не тестировал код, кроме как его компиляцию).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...