Как передать тип объекта с бизнес-уровня на уровень данных - PullRequest
3 голосов
/ 18 марта 2012

Я создаю n-уровневую архитектуру приложения. Разным уровням ничего не известно о внутренних реализациях друг друга, и связь между уровнями осуществляется через очень узкие интерфейсы с помощью IoC / DI.

Теперь я передаю бизнес-объекты (определенные на бизнес-уровне) на уровень данных. Сам по себе бизнес-уровень не знает, как и где данные фактически сохраняются (обычно база данных, но бизнес-уровень не должен этого знать). Бизнес-объекты передаются на уровень данных через реализацию IDataReader (этот подход также поддерживает массовую загрузку данных в будущих сценариях). Уровень данных считывает все данные из IDataReader и вызывает некоторую хранимую процедуру для сохранения данных в базе данных (если сохранен один объект, IDataReader возвращает «одну строку»).

Актуальная проблема здесь:

Поскольку я просто передаю IDataReader на уровень данных и отключаю данные от его типа, каков наилучший способ в этом случае определить место данных?

Пример, если я передаю фактический бизнес-объект типа «Пользователь» на уровень данных, то уровень данных должен сохранять данные в таблицу «Пользователь». В некоторых других случаях данные могут быть сохранены в другой структуре независимо от типа в бизнес-уровне.

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

Правильно ли решение уровня данных проверять поступающие данные и определять его место, или уровень данных должен представлять список «мест», в которых данные могут быть сохранены (enum?)?

Заранее спасибо!

/ Разъяснение

Опции, которые я вижу здесь: 1. Уровень данных дает список «мест», где данные могут быть сохранены 2. Уровень данных проверяет заданные аргументы (например, тип arg) и определяет, где хранить данные

Первый вариант штрафа; Что если я попытаюсь сохранить бизнес-объект типа «Продукт» в структуре, обычно используемой типом «Пользователь»

Второй вариант штрафа; Мне нужно сопоставить тип «Namespace1.Namespace2.User» с конкретной подпрограммой, которая сохраняет свои данные в таблицу «Пользователь». Так что вручную сделайте отображение для КАЖДОГО типа ...

/ Пояснение 2:

Теперь я получаю вот так:

service.Retrieve(typeof(Catalog), null, catalogArgs, e => catalogConverter.Read(e));

Итак, я передаю typeof (Catalog) слою данных ... поэтому у меня есть информация о типе в слое данных.

Теперь в слое данных мне нужно выбрать «Адаптер», который делает тяжелую работу для получения данных из базы данных. Я могу написать огромную структуру if / switch для выбора адаптера ... что разочаровывает. Также я могу написать атрибут и использовать его так:

[TypeAdapterAttribute("Namespace1.Namespace2.Catalog, and assembly info...")]
class CatalogAdapter { ... }

Тогда у меня есть код, который сопоставляет данные данного типа значению атрибута ...

... но с этой жестко закодированной строкой это немного наворочено и проблематично ...

Есть предложения ...?

/ Уточнение 3

У меня есть идея, что эту систему можно расширить с помощью «подключаемых бизнес-модулей». Эти модули содержат бизнес-объекты (и некоторую логику), которые не известны базовой бизнес-логике, а также уровень данных полностью не знает об этих бизнес-объектах, содержащихся в «подключенных сборках». Этот внешний бизнес-модуль не имеет ссылки на базовый бизнес-уровень или уровень данных. Когда бизнес-объект из этой внешней сборки сохраняется (= отправляется на уровень данных), уровень данных автоматически сохраняет его в стиле EAV (http://en.wikipedia.org/wiki/Entity%E2%80%93attribute%E2%80%93value_model) структура данных автоматически. Поскольку структура данных такого типа может иметь некоторые проблемы с производительностью, уровень данных должен иметь способ выбрать сохранение определенных типов бизнес-объектов в их собственной выделенной структуре данных (обычно это таблица с сопоставлением «один к одному» с этим типом). Таким образом, возникает проблема, как реализовать это «решение выбора»:)

Идея в том, что я могу создавать множество новых бизнес-объектов и сохранять все из них на уровне данных, фактически не кодируя ничего на уровне данных! Позже я могу создать собственные выделенные структуры данных для выбранных бизнес-объектов. При необходимости.

Ответы [ 2 ]

1 голос
/ 18 марта 2012

Если вы хотите создать свой собственный слой базы данных, который отключен от бизнес-уровня, вы также можете ввести отдельную сборку с контрактами

List<Customer> customers = DB.LoadCustomers();

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

List<Customer> customers = DataContext.Query<Customer>.Load();

или

Customer customer = DataContext.Query<Customer>.Load(custID);

O / R-преобразователи обычно работают следующим образом

List<Customer> customers = Context.Query<Customer>()
    .Where(cust => cust.Name.StartsWith("A"))
    .OrderBy(cust => cust.Name)
    .ToList();

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

(Примечание. Я не имею в виду определенные интерфейсы данных здесь.)


ОБНОВЛЕНИЕ:

Если вы хотите создать свой собственный слой базы данных, который не связан сНа бизнес-уровне вы также можете ввести отдельную сборку с контрактами

public interface ICustomer
{
    string LastName { get; set; }
    string FirstName { get; set; }
    ...
}

Как уровень данных, так и бизнес-уровень будут иметь ссылку на эти контракты.

На уровне данных выбудет иметь метод, аналогичный

public List<T> LoadAll<T>(Func<T> create)
{
    var list = new List<T>();
    if (T is ICustomer) {
        string sql = "SELECT * FROM tblCustomer";
        ...
        while (reader.NextResult()) {
            ICustomer cust = (ICustomer)create();
            cust.FirstName = reader.GetString("FirstName");
            ...
            list.Add((T)cust);
        }
    } else if (T is IOrder) {
        ...
    }
    return list;
}

На бизнес-уровне вы написали бы

List<ICustomer> customers = DbLayer.LoadAll<ICustomer>(() => new Customer());

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

1 голос
/ 18 марта 2012

Я бы порекомендовал вам использовать ORM (Entitiy Framework, NHibernate) или микро-ORM (PetaPoco, Dapper) для сопоставления ваших объектов с хранилищами данных.Изучите это и стреляйте, если у вас есть конкретный вопрос.

ОБНОВЛЕНИЕ: Я думаю, что я только что получил то, что вы спрашиваете.Вам необходимо определить новый метод в вашем слое данных для каждого типа.Итак:

public User GetUserById(int id);
public void SaveUser(User user);
public Product GetProductById(int id);
public void SaveProduct(Product product);
...