Проектирование взаимодействия с базой данных с соблюдением принципа единой ответственности

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

Производитель ‹== Датчики ‹==> ProbeSettings

У зонда есть производитель. Зонд имеет 1 набор настроек. Доступ к связанным объектам осуществляется по всему приложению, и, честно говоря, текущая реализация представляет собой беспорядок.

В настоящее время вот общее представление о том, как реализованы коммуникации и объекты:

public class Manufacturer
{
  public int ID; // Primary key, auto-incrementing on insert
  public string Name;
}

public class Probe
{
  public int ID; // Primary key, auto-incrementing on insert
  public int ManufacturerID;
  public string Name;
  public int Elements;
}

public class ProbeSettings
{
  public int ProbeID; // Primary key, since it is unique.
  public int RandomSetting;
}

// This class is a mess...
public static class Database
{
  public static string ConnectionString;

  public static void InsertManufacturer(Manufacturer manuf); // ID would be ignored here, since it's auto-incrementing.
  public static void InsertProbe(Probe probe); // Again, ID generally ignored.
  public static void InsertProbeSettings(ProbeSettings probeSet);

  public static Manufacturer[] GetAllManufacturer();
  public static Probe[] GetProbesFromManufacturer(int manufacturerID);
  public static Probe[] GetProbesFromManufacturer(Manufacturer manuf);
}

Я вижу здесь много проблем.

  1. Database делает слишком много.
  2. Эти объекты могут быть неизменяемыми при чтении на самом деле, единственная проблема возникает после вставки, я не уверен, какой идентификатор им был назначен, и вставленный объект теперь устарел.
  3. Каждый раз, когда классу нужно получить информацию из Database, мне пришлось бы добавить еще один метод Get для обработки определенного запроса.

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

public interface IDatabaseObject
{
    void Insert(Database db);
    bool Delete(Database db);
}

Каков хороший способ реализовать это?


person Will Eddins    schedule 20.01.2010    source источник
comment
Если вы найдете лучшее решение проблемы с репозиторием, дайте нам всем знать. Потому что ни одно решение, которое я когда-либо использовал, не обходилось без какой-то грубой чепухи по краям.   -  person    schedule 21.01.2010


Ответы (2)


Что ж, лучшим решением для работы с БД при сохранении SRP (или любого другого разумного шаблона) является использование какой-либо ORM (например, NHibernate).

Это позволит вам работать с классами как есть, вместо того, чтобы вручную перебрасывать их из/в БД.

Например, с NH ваши классы могут выглядеть так:

public class Manufacturer
{
  public string Name { ... }
  public IList<Probe> Probes { ... }
}

public class Probe
{
  public string Name { ... }
  public int Elements { ... }
  public ProbeSettings Settings { ... }
}

public class ProbeSettings
{
  public int RandomSetting;
}

Как видите, вам уже не нужен GetProbesFromManufacturer, так как вы можете просто перемещаться по коллекции внутри производителя.

Кроме того, ORM будет управлять идентификаторами объектов и сохранять их за вас. Таким образом, все, что вам нужно, это небольшое и фиксированное количество общих методов, таких как LoadById/LoadAll, которые хорошо вписываются в SRP класса, в котором доступ к данным. Также вам, вероятно, понадобится класс для каждого сложного и настраиваемого запроса к БД.

person Andrey Shchekin    schedule 20.01.2010
comment
Я использую Fluent NHibernate Automapping в течение последних нескольких месяцев и могу подтвердить, что все это правда. Мне НРАВИТСЯ возможность делать все на C# (включая LINQ) и (в основном) не беспокоиться о лежащей в основе реляционной модели. - person Tom Bushell; 21.01.2010
comment
Использование ORM — это то, чего мне не хватало, это правильно. Будь то NHibernate или DBLinq для MySQL, любой из них выполнит эту работу. Спасибо. - person Will Eddins; 22.01.2010

Похоже, вы ищете ORM. Поскольку вы работаете на C#, я предполагаю, что у вас есть доступ к LinqToSQL как часть платформы .NET. Linq может делать то, что вы ищете, а именно управлять базовым CRUD. операции. Подобные проекты, также заслуживающие внимания, — это Castle ActiveRecord и NHibernate.

person Alison R.    schedule 20.01.2010
comment
Я использую MySQL, но code.google.com/p/dblinq2007 может быть решение для LinqToSQL. Взгляните на это, спасибо. - person Will Eddins; 21.01.2010