Ты как бы изобретаешь колесо; 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.
}
(Это, очевидно, не производственный класс, это просто демонстрация техники; вы начинаете с запроса и не материализуете фактический список, пока не должны.)