Должен ли я создать в классе проекта BLL такой же, как класс poco в проекте DAL, и вернуть его в проект пользовательского интерфейса, если я хочу отобразить данные из базы данных?

#c# #asp.net-mvc #entity-framework #architecture

#c# #asp.net-mvc #entity-framework #архитектура

Вопрос:

У меня есть вопрос по архитектуре. У меня есть проект DAL с классами poco (эквивалентные таблицы в базе данных), проект BLL и проект пользовательского интерфейса. Проект пользовательского интерфейса имеет ссылку на проект BLL, а проект BLL имеет ссылку на проект DAL.

Я хотел бы отобразить в проекте пользовательского интерфейса данные, например, из таблицы Product из базы данных. Должен ли я создать в классе проекта BLL такой же, как класс poco в проекте DAL, вернуть его в проект пользовательского интерфейса и отобразить его?

Итак, это мой класс poco в DAL (эквивалентная таблица в базе данных):

 public class Product 
{

    public int  ID  {get; set; }
    public string  Name   {get; set; }
    public String  Address {get; set; }
}
  

В BLL я создал бизнес-объект, аналогичный классу poco выше:

 public class ProductBO
{
    public int ID { get; set; }
    public string Name { get; set; }
    public String Address { get; set; }
}
  

В BLL у меня также есть метод, который получает продукты из DAL и сопоставляет их с бизнес-объектами — ProductBO:

 public class ProductService
{
    public List<ProductBO> GetAllProducts()
    {
        List<ProductBO> productsBO = new List<ProductBO>();

        using (var context = NorthwindFactory.CreateContext())
        {
            List<Product> products = context.Product.ToList();

            foreach (var product in products)
            {
                productsBO.Add(new ProductBO { ID = product.ID, Address = product.Address, Name = product.Name });
            }
        }

        return productsBO;
    }
}
  

И теперь в проекте пользовательского интерфейса в контроллере я вызываю службу из BLL, которая возвращает список, и в представлении я могу отображать данные с помощью бизнес-объекта ProductBO.

 @model IEnumerable<WebApplication1.BLL.BusinessObjects.ProductBO>

<table class="table">
    <tr>
        <th>
            @Html.DisplayNameFor(model => model.Name)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Address)
        </th>
    </tr>
@foreach (var item in Model) {
    <tr>
        <td>
            @Html.DisplayFor(modelItem => item.Name)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.Address)
        </td>
    </tr>
}
</table>
  

Это правильный подход к архитектуре?

Комментарии:

1. Если бы это был я, я бы разделил объекты домена между DAL и BLL. Таким образом, вы уменьшаете количество дублирующегося кода. Для представлений, если потребуется, я создам модели представлений, с которыми они взаимодействуют, но эти модели представлений также используют объекты домена. Таким образом, вам также не нужно конвертировать между Product и ProductBO

Ответ №1:

Ну, нет единственно правильного подхода. Но я стараюсь избегать создания набора классов DAL. Современные ORM позволяют работать с классами POCO. Да, есть некоторые ограничения (например, перечисления), но ИМХО не стоит создавать две копии каждого бизнес-объекта и сопоставлять их. Итак, я использую один объект POCO, который находится в сборке бизнес-логики. Entity Framework работает с этим объектом, сохраняет и загружает его из базы данных. Нет сопоставления.

Уровень представления отличается. Обычно у вас есть несколько представлений одного и того же объекта на разных страницах. Вы также должны использовать разные атрибуты аннотации данных для установки ограничений на модели представления или некоторые UIHints. Это загрязнило бы ваш бизнес-объект логикой, специфичной для пользовательского интерфейса. Также вам часто нужно будет отображать форматированные или измененные данные, например, полное имя вместо имени и фамилии вашего лица. сущность. Итак, здесь я не использую свои бизнес-объекты POCO, а вместо этого создаю модели представления.

С вашим образцом продукта этот подход будет выглядеть так:

  • Сборка бизнес-логики имеет объект POCO Product
  • Сборка с сохранением ссылается на сборку бизнес-логики и использует то же самое Product
  • Проект пользовательского интерфейса имеет разные модели представления и т.д. ProductViewModel BriefProductViewModel Он также отвечает за сопоставление Product и просмотр моделей. Примечание — ручное сопоставление занимает много времени. Я предлагаю вам использовать какую-нибудь библиотеку сопоставления, например AutoMapper или ValueInjecter

Комментарии:

1. Что-то должно быть не так в вашем объяснении. Я полагаю, что ваша сборка BL ссылается на «сборку сохранения», чтобы использовать ее, и вы также говорите, что ваша сборка сохранения ссылается на BL для использования Product . Это четкая циклическая ссылка. Как VS справляется с этим? (Должен быть какой-то скрытый ингредиент: DI), интерфейсы проекта wuth?) Я видел, что в ответе @Maarten используется та же техника. Интересно, как

2. 1 за упоминание о том, что дополнительная модель «постоянства» обычно не стоит дополнительных усилий — ORM уже отчасти играют эту роль. Дополнительные уровни абстракции всегда являются компромиссами между гибкостью и сложностью / стоимостью. Также смотрите Эту статью: blog.ploeh.dk/2012/02/09/IsLayeringWorththeMapping

3. @JotaBe «Я полагаю, что ваша сборка BL ссылается на сборку persistence» => почему? BL не должен решать, как и когда сохраняются его объекты. Для этого не требуется знание уровня сохраняемости.

4. @guillaume31. Я пытаюсь понять, как это возможно. Например, если вы делаете заказ, используя BL «Order.New (некоторые данные)», бизнес-уровень должен где-то хранить это, поэтому он должен вызывать уровень постоянства, поэтому он должен иметь зависимость от этого уровня. Я понимаю, что BL не нужно знать, как, но BL решает, когда. Как BL может хранить данные, если он не ссылается на уровень сохранения ?. Если этот проект не определяет интерфейсы и не использует DI для реализации этих интерфейсов, я не знаю, как это возможно.

5. @JotaBe как я уже сказал в ответе, BL не ссылается на сборку сохранения. В нем есть сущности и службы, а также определение интерфейсов репозитория, которые реализованы в сборке сохранения. Службы BL определяют, когда использовать репозитории. Приложение ссылается на обе сборки — ASP.NET веб-сайт в данном случае. Реализация репозиториев, предоставляемых службам BL основным приложением. Вот почему BL ничего не знает о постоянстве

Ответ №2:

Вы должны определить свои объекты POCO (domain) в вашем проекте BLL, поскольку они являются бизнес-объектами.

Ваш DAL должен иметь ссылку на BLL, а не наоборот.

Лично я сторонник архитектуры Onion, которая помещает ваш домен в центр вашего приложения. Любой добавляемый вами слой должен ссылаться только внутрь, а не наружу. Итак, по этому определению ваш BLL является центром и ни на что не ссылается. Добавьте слой DAL, и он может ссылаться только внутрь, поэтому он может ссылаться на BLL. Уровень пользовательского интерфейса также ссылается только на BLL, но не на DAL, поскольку DAL является деталью реализации.

Комментарии:

1. Зачем DAL когда-либо нужна ссылка на BLL

2. Возможно, использовать объекты POCO, чтобы сохранить их в БД.

3. в примере OPs POCO находятся в DAL

4. Так, может быть, как сказал @3dd — я должен создать новый проект с классами poco, а проекты DAL, BLL, UI должны иметь ссылки на проект с классами poco?

5. Мой комментарий к другому ответу также применим к этому. Для кого-то, кто, вероятно, никогда не внедрял IoC, это должно выглядеть как «черная магия».