Разделение извлечения данных и бизнес-объектов между уровнями DAL и BLL

9

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

Бизнес-объекты на уровне доступа к данным

У меня есть хранилище, и бизнес-уровни вызывают хранилище для получения данных. Например, скажем, у меня есть следующие классы для BLL и DAL:

class BllCustomer
{
    public int CustomerId {get; set;}
    public String Name {get; set;}
    public BllAddress Address {get; set;}
}

class BllAddress
{
     public int AddressId {get; set;}
     public String Street {get; set;}
     public String City {get; set;}
     public String ZipCode {get; set; }
}

class DalCustomer 
{
    public int CustomerId {get; set;}
    public String Name {get; set;}
    public int AddressID {get; set;}
}

class DalAddress
{
     public int AddressId {get; set;}
     public String Street {get; set;}
     public String City {get; set;}
     public String ZipCode {get; set; }
}

Если BLL хочет получить объект Customer, он вызовет GetCustomerById (customerId) в DAL.

Следующее - мои проблемы, которые я не мог понять ясно:

  1. Я не вижу, как определить, какой объект должен возвращать GetCustomerById в DAL? Должен ли он вернуть BllCustomer или DalCustomer?

  2. Где должен быть поиск (и / или преобразование в бизнес-объект) адреса, связанного с клиентом?

Если DAL возвращает объекты Dal, логика для извлечения и заполнения адреса может быть только в BLL. Если DAL возвращает объекты BLL, то логика для извлечения и заполнения адреса может быть либо в BLL, либо в DAL. В настоящее время DAL возвращает бизнес-объекты, и логика для его заполнения находится в DAL.

Из того, что я прочитал, я думаю, что нет правильного или неправильного. По ссылке, приведенной выше, есть люди, которые говорят одно, а другие говорят другое. Но как определить, что лучше всего подойдет для моего случая?

Любая помощь будет оценена.

ShamirDaj
источник
2
Мой первый вопрос будет: это унаследованное приложение? Существует множество фреймворков ORM, которые делают этот вид кода устаревшим, и я призываю вас рассмотреть такую ​​структуру ...
JDT
@ JDT Я не уверен, что вы имеете в виду, я использую Entity Framework и у меня точно такая же проблема. Насколько я понимаю, вы не должны использовать ORM в качестве объектов домена, так где же сделан перевод?
псевдокодер
Почему ваша платформа ORM не возвращает объекты, которые также являются объектами домена?
JDT
3
@JDT ORM (в данном случае EF) возвращает классы сущностей, которые обычно представляют одну таблицу базы данных на класс. Обычно это похоже на, но не обязательно совпадает с классами домена. Может быть, вы просто говорите, что в качестве классов домена можно использовать классы ORM? Я читал в ряде мест, что это нет-нет.
псевдокодер

Ответы:

5

Я не вижу, как определить, какой объект должен возвращать GetCustomerById в DAL? Должен ли он вернуть BllCustomer или DalCustomer?

Он должен возвращать объект DalCustomer , возвращение объекта BllCustomer нарушит принцип единоличной ответственности . Вы можете просматривать объект DalCustomer как интерфейс или контракт, используемые бизнес-уровнем (или потребителем). По сути, если он возвращает BllCustomer, DAL должен обслуживать каждый объект бизнес-уровня, который вызывает его или может вызвать его.

Где должен быть поиск (и / или преобразование в бизнес-объект) адреса, связанного с клиентом?

Преобразование должно быть сделано в виде модели или менеджера. Вам нужен посредник, чтобы позвонить в службу или компонент доступа к данным. Если вы чувствуете необходимость, у вас может быть преобразование в вашем объекте BllCustomer . Но затем, когда вы меняете свой DAL, например, с MSSQL на Oracle, возвращаемый объект (или интерфейс) должен оставаться прежним.

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

Derika
источник
4

Ваш репозиторий должен возвращать BLL или объект домена. скорее всего, вам вообще не нужен объект DAL.

public class Customer
{
    public string Name {get; private set;}
    public Customer(string name)
    {
        this.Name = name;
    }
}

public class Repository
{
    public Customer GetCustomer(string id)
    {
        //get data from db
        return new Customer(datarow["name"]);
    }
}
Ewan
источник
Должна ли BLL или отдельная библиотека классов предоставлять интерфейсы вместо конкретных классов, таких как Customer?
Йола
1
Нет. Хорошо выставлять конкретные классы. Будет полезен интерфейс для хранилища
Ewan
3

Как правило, DAL не знает BLL. Подумайте об этом так, другое приложение с другим BLL может использовать один и тот же DAL. Приложение / модуль Payables и приложение Receivables для одной и той же компании будут обмениваться данными (клиенты, сборы, платежи и т. Д.). Попытка иметь одну DLL-библиотеку со знанием более чем одного BLL будет очень трудной и ненужной. Это также позволит вам изменить хранилище данных, не влияя на BLL (если вы не нарушаете интерфейсы).

Теперь вы можете передать объект DAL в BLL или создать третий набор объектов: Entity. Они будут содержать только значения, которые будут переданы вместе. DAL будет ссылаться на объект и взаимодействовать с вашим хранилищем / базой данных, а BLL будет обрабатывать всю логику и ссылаться на DAL.

class EntCustomer
{
    public int CustomerId {get; set;}
    public String Name {get; set;}
    public BllAddress Address {get; set;}
}
class BllCustomer
{
   //reference EntCustomer, DalCustomer and handle business rules/logic
}

class DalCustomer 
{
   //reference EntCustomer and interact with data storage
}
JeffO
источник
Спасибо за ваш комментарий. Я согласен с вами .. Я уже вижу, что наш DAL / (Repository) уже заполнен логикой, например, если тип A, затем перейдите к извлечению данных из таблицы B, но если тип C, то перейдите к извлечению данных из таблицы C. Но я запутался с вашим примером использования EntCustomer. В моем случае DalCustomer является зеркалом таблиц в БД. Можете ли вы привести больше примеров, как используется EntCustomer или почему я должен его использовать и какие преимущества он дает. Я думаю изменить DAL, чтобы вернуть DalObjects в BLL. Bll остановит преобразование в Business Objs, извлечет и заполнит вложенный объект.
ShamirDaj
Можете ли вы дать больше отзывов?
ShamirDaj
Я думаю, что целью Ent-объектов является просто передача данных между DAL и BLL. Ваши классы DAL могут продолжать отражать структуру db, но эти классы будут внутренними для DAL. Когда BLL запрашивает данные из DAL, DAL извлекает необходимые объекты DAL из базы данных (dalcustomer + daladdress), создает из них экземпляр EntCustomer и возвращает его в BLL.
artokai
-1

DAL должен быть независимым от BL, а BL - зависимым от DAL. Ваш пользовательский интерфейс должен иметь доступ только к данным через BL. Рекомендуется возвращать DataTable или DataRow из DAL, а затем преобразовывать DataTable / DataRow в объекты BL. Когда ваш пользовательский интерфейс должен получить доступ к данным, он может получить доступ из BL. Таким образом, пользовательский интерфейс не зависит от имени столбца и типа базы данных (SQL Server, Oracle ..). Таким образом, ваш интерфейс будет полностью независим от DAL. Лично я предпочитаю имя класса, например "CustomerBL", не используйте слово BL в начале имени класса.

Ниже см. Пример кода.

//Customer Class
class BllCustomer
{
    public int CustomerId { get; set; }
    public String Name { get; set; }
    public BllAddress Address { get; set; }

    public static BllCustomer GetByCustomerId(int id)
    {
        DataRow dr = DalCustomer.GetByCustomerId(id);
        if (dr == null)
            return null;
        BllCustomer oCust = new BllCustomer();
        oCust.CustomerId = int.Parse(dr["CustomerId"].ToString());
        //Do for other class members and load values

        return oCust;
    }
}


class DalCustomer
{

    public static DataRow GetByCustomerId(int id)
    {
        //Get Data row from Database and return Datarow
        DataRow CustomerRow = GETFROMDATABASE("SELECT * from CUSTOMER");
        return CustomerRow;
    }
}
Jigneshk
источник
Эээ ... Не значит ли это, что ваш BLL должен знать формат / структуру ваших таблиц данных? ...
Пол