Як я маю інкапсулювати доступ до бази даних?


10

Наведіть кілька прикладів гарних структур класу, які використовуються для управління доступом до бази даних? Я прихильник інкапсуляції класів і вважаю за краще, щоб контейнери (наприклад, машина) не виконували завдань із бази даних.

Я також хотів би можливість в майбутньому легко вносити такі речі, як кеш бази даних.

Я часто беру схему класів контейнерів у комплекті з геттерами та сеттерами для перевірки та доступу до бази даних, що виконуються одним одиночним класом. За словами, це часто змішується між двома і стає досить заплутаним.

Вибачте, якщо моє питання важко зрозуміти; Я не зовсім впевнений в умовах, що стосуються баз даних. Будь ласка, попросіть роз'яснити, якщо це необхідно.


Ви розглядали можливість використання ORM для прив'язки класів до баз даних, таких як Wt :: Dbo ?
user52875

Відповіді:


11

Я віддаю перевагу шаблону репозиторію, щоб інкапсулювати доступ до даних. У двох словах, сховище відповідає за завантаження всіх даних, необхідних для конкретного об'єкта. Скажімо, у вас є об'єкт "Автомобіль", як у вашому прикладі. Але всі атрибути автомобіля, марка, модель, рік, власники, функції (програвач CD, 4wd тощо) зберігаються в різних таблицях по всій базі даних. Репозиторій визначає, як завантажувати та зберігати дані. Якщо потрібно кілька менших запитів, добре, але це потрібно знати лише шаблону репозиторію. Службовий рівень, який викликає сховище, повинен знати лише те, до якого сховища потрібно звернутися.

Потім їх можна поєднувати з одиницею роботи . Тож у вашому прикладі сервісний рівень скаже, що йому потрібно завантажити автомобільну сутність, він має якийсь унікальний ідентифікатор і передає цей ідентифікатор до сховища. Репозиторій повертає автомобільну особу. Деякий інший код маніпулює суттю автомобіля і відсилає цю сутність в сховище, щоб її можна було зберегти.

Якщо ви дійсно хочете все вийти, шар сховища відкриє лише інтерфейси, такі як ICarRepository. Репозиторій міститиме фабрику, яку службовий рівень використовуватиме для отримання інтерфейсу ICarRepository. Весь доступ до бази даних буде приховано за інтерфейсом, що набагато полегшує тестування блоків.


Все приємно, окрім останнього біта про інтерфейси, які в c ++ не існують (якщо тільки ОП не означав тегувати c ++). Мені дуже цікаво бачити реалізацію шаблону репозиторію в C ++, оскільки я хочу його використовувати з QT. Я вражений, що в Інтернеті немає нічого корисного = [
johnildergleidisson

6

Я використовував шаблон стратегії, щоб інкапсулювати доступ до даних. Ця схема дозволяє приховати тип пам’яті, який ви використовуєте за загальним інтерфейсом. В інтерфейсі визначте свої методи доступу до даних, не зважаючи на тип пам’яті (файл, база даних, веб). Потім для вашого поточного вибору пам’яті в класі, що реалізує інтерфейс стратегії, реалізуйте дані доступу до даних. Таким чином, ваша програма не дбає про джерело даних, яке ви використовуєте.

Ви також можете створити сервісний рівень, який використовує поточний екземпляр стратегії зберігання даних, щоб визначити більше конкретних додатків, а не змішувати доступ до даних та логіку бізнесу разом.


Отже, ви б додали клас доступу для кожного типу або один великий клас для всіх?
Will03uk

особисто я також розглядаю можливість прийняття чітких кастингів для всіх даних, які надходять з дикого середовища на мій сервер / додаток.
user827992

+1 мені подобається зовнішній вигляд цього шаблону, але я відчуваю (за масштабами мого проекту), керувати кожним алгоритмом окремо для бази даних буде важко; хоча я обов'язково буду використовувати це в інших додатках. Лямбди повинні добре доповнити це.
Will03uk

1

Це приклад заводської моделі бази даних;

using System.Reflection;
using System.Configuration;

public sealed class DatabaseFactory
{
    public static DatabaseFactorySectionHandler sectionHandler = (DatabaseFactorySectionHandler)ConfigurationManager.GetSection("DatabaseFactoryConfiguration");

    private DatabaseFactory() { }

    public static Database CreateDatabase()
    {
        // Verify a DatabaseFactoryConfiguration line exists in the web.config.
        if (sectionHandler.Name.Length == 0)
        {
            throw new Exception("Database name not defined in DatabaseFactoryConfiguration section of web.config.");
        }

        try
        {
            // Find the class
            Type database = Type.GetType(sectionHandler.Name);

            // Get it's constructor
            ConstructorInfo constructor = database.GetConstructor(new Type[] { });

            // Invoke it's constructor, which returns an instance.
            Database createdObject = (Database)constructor.Invoke(null);

            // Initialize the connection string property for the database.
            createdObject.connectionString = sectionHandler.ConnectionString;

            // Pass back the instance as a Database
            return createdObject;
        }
        catch (Exception excep)
        {
            throw new Exception("Error instantiating database " + sectionHandler.Name + ". " + excep.Message);
        }
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.