Где объекты объединяют / объединяют данные в трехуровневой модели? - PullRequest
2 голосов
/ 05 июня 2010

Вероятно, это простая 3-уровневая задача. Я просто хочу убедиться, что мы используем лучшие практики для этого, и я пока не очень знаком со структурами.

У нас есть 3 уровня:

  • GUI: ASP.NET для уровня презентаций (первая платформа)
  • BAL: бизнес-уровень будет обрабатывать логику на веб-сервере в C #, поэтому мы оба можем использовать ее для веб-форм / MVC + веб-сервисы
  • DAL: LINQ to SQL на уровне данных, возвращающий BusinessObjects не LINQ.
  • БД: SQL будет Microsoft SQL-сервер / Express (еще не определено).

Давайте подумаем о настройке, где у нас есть база данных [Персоны]. Все они могут иметь несколько [Address] es, и у нас есть полный список всех [PostalCode] и соответствующих названий городов и т. Д.

Дело в том, что мы объединили много деталей из других таблиц.

{Отношения} / [таблица]

  • [Person]: 1 --- N: {PersonAddress}: M --- 1: [Address]
  • [Адрес]: N --- 1: [Почтовый индекс]

Теперь мы хотим построить DAL для Персона. Как должен выглядеть PersonBO и когда происходит соединение? Является ли проблемой бизнес-уровня получение всех названий городов и возможных адресов pr. Человек? или DAL должен завершить все это перед возвратом PersonBO в BAL?

Class PersonBO 
{
    public int ID {get;set;}
    public string Name {get;set;}
    public List<AddressBO> {get;set;} // Question #1
} 

// Q1: извлекаем ли мы объекты перед возвратом PersonBO и вместо этого это должен быть массив? или это совершенно неправильно для n-уровня / 3-уровня ??

Class AddressBO 
{
    public int ID {get;set;}
    public string StreetName {get;set;}
    public int PostalCode {get;set;} // Question #2
} 

// Q2: мы делаем поиск или просто оставляем Индекс для последующего поиска?

Может кто-нибудь объяснить, в каком порядке тянуть какие объекты? Конструктивная критика очень приветствуется. : О)

1 Ответ

1 голос
/ 05 июня 2010

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

Способ, которым ORM, такие как Linq to SQL, Entity Framework и NHibernate, делают это, представляет собой метод, называемый отложенная загрузка ассоциаций (который может быть переопределен при активной нагрузке).

Когда вы открываете Person, он не загружает Address, пока вы специально не попросите его, и в этот момент произойдет еще одно обращение к базе данных (отложенная загрузка). Вы также можете указать для каждого запроса, что вы хотите, чтобы Address загружался для каждого человека (полная нагрузка).

В некотором смысле, с этим вопросом вы в основном спрашиваете, должны ли вы выполнять ленивые или энергичные загрузки AddressBO для PersonBO, и ответ таков: ни то, ни другое. Не существует единого подхода, который бы универсально работал. По умолчанию вы, вероятно, должны загружаться лениво, чтобы не делать много ненужных объединений; чтобы осуществить это, вам придется собрать PersonBO с ленивым механизмом загрузки, который поддерживает некоторую ссылку на DAL. Но вы все равно захотите иметь возможность загружать данные, которые вам необходимо будет встроить в логику «доступа к бизнесу».

Другой вариант, если вам необходимо вернуть набор данных с высокой степенью настройки и конкретными свойствами, заполненными из множества разных таблиц, - вообще не возвращать PersonBO, а вместо этого использовать Объект передачи данных (DTO). Если вы реализуете механизм отложенной загрузки по умолчанию, вы можете иногда заменить его версией с активной загрузкой.


К вашему сведению, ленивые загрузчики в платформах доступа к данным обычно создаются с логикой загрузки в самой ассоциации:

public class PersonBO
{
    public int ID { get; set; }
    public string Name { get; set; }
    public IList<AddressBO> Addresses { get; set; }
}

Это просто POCO, волшебство происходит в реальной реализации списка:

// NOT A PRODUCTION-READY IMPLEMENTATION - DO NOT USE

internal class LazyLoadList<T> : IList<T>
{
    private IQueryable<T> query;
    private List<T> items;

    public LazyLoadList(IQueryable<T> query)
    {
        if (query == null)
            throw new ArgumentNullException("query");
        this.query = query;
    }

    private void Materialize()
    {
        if (items == null)
            items = query.ToList();
    }

    public void Add(T item)
    {
        Materialize();
        items.Add(item);
    }

    // Etc.
}

(Это, очевидно, не производственный класс, это просто демонстрация техники; вы начинаете с запроса и не материализуете фактический список, пока не должны.)

...