Jak powinienem obudować dostęp do bazy danych?

10

Jakie są przykłady dobrych struktur klasy używanych do zarządzania dostępem do bazy danych? Jestem fanem enkapsulacji klas i wolałbym, aby kontenery (np. Samochód) nie wykonywały zadań bazy danych.

Chciałbym również mieć możliwość łatwego upuszczania rzeczy takich jak pamięć podręczna bazy danych w przyszłości.

Często biorę wzorzec klas kontenerów, wraz z modułami pobierającymi i ustawiającymi do sprawdzania poprawności i dostępu do bazy danych wykonywanymi przez pojedynczą klasę singleton. To powiedziawszy, często miesza się między nimi i staje się dość mylące.

Przepraszam, jeśli moje pytanie jest trudne do zrozumienia; Nie mam absolutnej pewności co do warunków dotyczących baz danych. W razie potrzeby prosimy o wyjaśnienia.

Will03uk
źródło
Czy rozważałeś użycie ORM do łączenia klas z bazami danych, takimi jak Wt :: Dbo ?
user52875,

Odpowiedzi:

11

Wolę wzorzec repozytorium od enkapsulacji dostępu do danych. Krótko mówiąc, repozytorium jest odpowiedzialne za ładowanie wszystkich danych wymaganych dla określonego obiektu. Powiedz, że masz obiekt samochodowy, jak w twoim przykładzie. Ale wszystkie atrybuty samochodu, marki, modelu, roku, właścicieli, funkcji (odtwarzacz CD, napęd na 4 koła itp.) Są przechowywane w różnych tabelach w całej bazie danych. Repozytorium określa sposób ładowania i zapisywania danych. Jeśli potrzeba wielu mniejszych zapytań, dobrze, ale tylko wzorzec repozytorium musi o tym wiedzieć. Warstwa usługi wywołująca repozytorium musi tylko wiedzieć, które repozytorium ma zostać wywołane.

Można to następnie połączyć z wzorcem jednostki pracy . Tak więc w twoim przykładzie warstwa usługi powiedziałaby, że musi załadować jednostkę samochodu, ma jakiś unikalny identyfikator i wysyła ten identyfikator do repozytorium. Repozytorium zwraca jednostkę samochodu. Niektóre inne kody manipulują jednostką samochodu i odsyłają ją do repozytorium, aby można ją było zapisać.

Jeśli naprawdę chcesz wyjść na całość, warstwa repozytorium udostępnia tylko interfejsy, takie jak ICarRepository. Repozytorium zawierałoby fabrykę, której warstwa usługi użyłaby do uzyskania interfejsu ICarRepository. Cały dostęp do bazy danych byłby ukryty za interfejsem, co znacznie ułatwia testowanie jednostek.

bwalk2895
źródło
Wszystko ładnie, z wyjątkiem ostatniego bitu o interfejsach, które w c ++ nie istnieją (chyba że OP nie chciał oznaczać c ++). Jestem bardzo ciekawy implementacji Wzorca Repozytorium w C ++, ponieważ chcę go używać z QT. Dziwi mnie, że nie ma nic użytecznego online = [
johnildergleidisson
6

Użyłem Wzorca Strategii do enkapsulacji dostępu do danych. Ten wzór pozwala ukryć rodzaj używanej pamięci za wspólnym interfejsem. W interfejsie określ metody dostępu do danych, nie uwzględniając typu magazynu (plik, baza danych, sieć). Następnie dla bieżącego wyboru miejsca do przechowywania, w klasie realizującej interfejs strategii, zaimplementuj szczegóły dostępu do danych. W ten sposób aplikacja nie dba o używane źródło danych.

Można również zbudować warstwę usługi, która wykorzystuje bieżącą instancję strategii przechowywania danych do definiowania bardziej szczegółowych informacji specyficznych dla aplikacji zamiast mieszania dostępu do danych i logiki biznesowej.

Mike L.
źródło
Czy dodałbyś klasę dostępu dla każdego typu lub jedną dużą klasę dla wszystkich?
Will03uk,
osobiście zastanowiłbym się również nad przyjęciem jawnych rzutowań dla wszystkich danych, które przychodzą z dziczy do mojego serwera / aplikacji.
user827992,
+1 Podoba mi się wygląd tego wzorca, ale wydaje mi się (w skali mojego projektu), że zarządzanie każdym algorytmem osobno dla bazy danych będzie trudne; chociaż z pewnością użyję tego w innych aplikacjach. Jagnięta muszą to dobrze uzupełniać.
Will03uk
1

To jest przykład wzorca fabrycznego bazy danych;

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);
        }
    }
}
theclai
źródło