it-swarm.com.ru

Шаблон проектирования для уровня доступа к данным

Вы можете почувствовать, что это домашнее задание, за это я извиняюсь. Я искал, но не мог найти правильный ответ.

Итак, мой вопрос:

У меня есть несколько классов, и у каждого класса есть метод для сохранения. Поэтому я создал отдельный класс для обработки базы данных.

namespace HospitalMgt.Data
{
    public static class DBConnection
    {
        public static string constr = "Data Source=ABD;Initial Catalog=HospitalMgt;User Id=sa;Password=123";
        public static SqlConnection con;
      //  public static SqlCommand com;

        public static SqlConnection OpenConnection()
        {
            con= new SqlConnection(constr);
            con.Open();
            return con;
        }

    }
}

Однако я не думаю, что это целесообразно для реализации всех классов с классом DBConnection.

Мой вопрос :

  1. Какой шаблон проектирования подходит для преодоления этой проблемы?
  2. Это хорошая практика для создания DBConnection как класс? (Или это должен быть интерфейс)

Я нашел несколько статей о слоях DA с использованием метода Factory, но, насколько мне известно, этот шаблон не подходит для моей ситуации. 

11
DevT

Обычно, если я не могу использовать какой-либо существующий фреймворк, я использую шаблоны Repository и Active. 

Для простоты вы можете использовать только шаблон Repository. Я обычно определяю это так:

//  Define a generic repository interface
public interface IRepository<Key, E> where E:IEntity<Key>>{
    void Add(E entity);
    void AddRange(IEnumerable<E> entities);
    IEntity<Key> Get(Key key);
    IEnumerable<E> GetRange(IEnumerable<Key> keys);
    IEnumerable<E> GetAll();
    //  ..., Update, Delete methods
}

//  Create an abstract class that will encapsulate the generic code
public abstract class Repository<K, E> where E:IEntity<K>>:IRepository<K, E>{

    protected Repository(/*parameter you may need to implement the generic methods, like a ConnectionFactory,  table name, entity type for casts, etc */){}

    public override void Insert(IEntity<Key> entity){
        //  do the insert, treat exceptions accordingly and encapsulate them in your own and more concise Exceptions, etc
    }
    //  ...
}

//  Create the entities classes, one for each table, that will represent a row of that table
public class Car: IEntity<String>{/* Properties */}

//  Create a specific repository for each table
//  If the table have a composed key, just create a class representing it
public CarRepository: Repository<String, Car>{

    public CarRepository(){/* pass the base parameters */}

    // offer here your specific operations to this table entity
    public IEnumerable<Car> GetByOwner(PersonKey ownerKey){
        //  do stuff
    }
}

Теперь у вас есть достаточно инструментов для работы с базой данных, но при желании вы можете использовать шаблон Active . Простой пример:

public class Person:IEntity<PersonKey>{
    public PersonKey Key{get;}
    public IEnumerable<Car> OwnedCars{
        get{
            CarRepository rep = DBSingletons.Cars;
            return rep.GetByOwner(this.Key);
        }
        set{
            //  do stuff
        }
    }
}

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

//  simple example
ITransaction t = TransactionFactory.GetNewTransaction();
t.begin();
try{
    //  create person entity
    personRepository.Add(person, t);
    //  create cars assigned to person
    carRepository.AddRange(cars, t);
    t.commit();
}catch(Exception){
    t.rollback();
}

Просто убедитесь, что вы действительно хотите создать свой собственный DAL, так как он может оказаться чрезвычайно сложным, особенно пытаясь разработать наиболее универсальное решение.

11
João Simões

Я предлагаю использовать ORM, Entity Framework или NHibernate. Тогда вам не нужно беспокоиться о контексте БД или создавать операторы SQL.

5
Richard Schneider

Прежде всего, я хотел бы порекомендовать вам статью «Шаблоны проектирования для персистентности данных» Джереми Миллера .

Существует несколько шаблонов уровня доступа к данным:

  1. Шаблон активной записи ( wiki , Подробная информация ).
  2. Шаблон репозитория ( Подробная информация ).
4
Sergey Brunov

Я предлагаю вам использовать RepositoryBase для всех этих общих операций. Если вы решите использовать ORM для доступа к данным, хорошо подумать о реализации репозиториев на основе репозитория универсального типа. 

Вот хорошая статья об этом:

http://lostechies.com/jimmybogard/2009/09/03/ddd-repository-implementation-patterns/

2
Pablo Rodríguez

Это слишком старое, но только что пришло время ответить на этот вопрос и не смог удержаться, чтобы оставить свои мысли.

Я нашел Репозиторий с UnitOfWork с некоторым спуском ORM - хороший подход. Это минимизирует большинство проблем.

UoW, упомянутый в ссылке выше, может быть введен в репозиторий. Это увеличивает гибкость использования. Кроме того, весь код связи с БД централизован в одном месте. Пример не завершен, но является точкой запуска.

Шаблон репозитория, упомянутый в ссылке выше, на самом деле является базовым базовым классом. Вы можете создать новый класс для каждого вашего конкретного репозитория, производного от него.

Общий репозиторий считается анти-паттерном; Есть много статей в Интернете, которые объясняют это.

Почему общий репозиторий является антишаблоном?

  1. Репозиторий является частью моделируемого домена, и этот домен не является универсальным .
    • Не каждая сущность может быть удалена.
    • Не каждая сущность может быть добавлена
    • Не у каждого объекта есть хранилище.
    • Запросы сильно различаются; API хранилища становится таким же уникальным, как и сам объект.
    • Для GetById() типы идентификаторов могут быть разными.
    • Обновление определенных полей (DML) невозможно.
  2. За общий механизм запросов отвечает ORM .
    • Большинство ORM предоставляют реализацию, которая очень похожа на Generic Repository.
    • Репозитории должны реализовывать СПЕЦИАЛЬНЫЕ запросы для сущностей, используя общий механизм запросов, предоставляемый ORM.
  3. Работа с составными ключами невозможна.
  4. В любом случае, это приводит к утечке логики DAL в службах.
    • Критерии предиката, если вы принимаете их в качестве параметра, должны быть предоставлены из сервисного уровня. Если это специфичный для ORM класс, он пропускает ORM в Сервисы.

Я предлагаю вам прочитать эти ( 1 , 2 , 3 , 4 , 5 ) статьи, объясняющие, почему универсальный репозиторий является anit-pattern.

Решение:

  1. Напишите абстрактный универсальный репозиторий, который обернут конкретным репозиторием. Таким образом, вы можете управлять общедоступным интерфейсом, но при этом иметь возможность повторного использования кода, получаемого из общего репозитория.
  2. Используйте универсальный репозиторий, но используйте композицию вместо наследования и не выставляйте ее домену в качестве контракта.

В любом случае, не подвергайте Generic Repository вызывающему коду. Также не выставляйте IQueryable из конкретных репозиториев.

1
Amit Joshi