Лучший «шаблон» для уровня доступа к бизнес-объектам - PullRequest
16 голосов
/ 14 марта 2009

Я пытаюсь найти самый чистый способ сделать это.

В настоящее время у меня есть объект клиента:

public class Customer
{
    public int Id {get;set;}
    public string name {get;set;}
    public List<Email> emailCollection {get;set}
    public Customer(int id)
    {
        this.emailCollection = getEmails(id);
    }
}

Тогда мой объект электронной почты тоже довольно простой.

public class Email
{
    private int index;
    public string emailAddress{get;set;}
    public int emailType{get;set;}
    public Email(...){...}
    public static List<Email> getEmails(int id)
    {
        return DataAccessLayer.getCustomerEmailsByID(id);
    }
}

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

Так где и как я могу улучшить это?

Должен ли мой DataAccessLayer вместо этого возвращать DataTable и оставлять его до объекта Email для анализа и возврата списка обратно клиенту?

Я полагаю, что "Фабрика", возможно, неправильное слово, но должен ли я иметь другой тип EmailFactory, который берет DataTable из DataAccessLayer и возвращает List в объект Email? Я думаю, что такие звуки излишни ...

Это даже правильная практика, когда мой Email.getEmails (id) используется как статический метод?

Я мог бы просто скинуть себя, пытаясь найти и применить лучший «шаблон» к тому, что обычно было бы простым заданием.

Спасибо.


Последующие действия

Я создал рабочий пример, в котором мой объект Domain / Business извлекает запись клиента по идентификатору из существующей базы данных. Файлы отображения xml в nhibernate действительно аккуратны. После того, как я последовал руководству по настройке фабрик сессий и хранилищ, извлечение записей из базы данных было довольно простым.

Однако я заметил огромный удар по производительности.

Мой оригинальный метод состоял из хранимой процедуры в БД, которая была вызвана объектом DAL, который проанализировал набор результатов в моем домене / бизнес-объекте.

Я использовал свой первоначальный метод - 30 мс, чтобы получить одну запись клиента. Затем я выбрал метод nhibernate, взяв 3000 мсек для получения той же записи.

Я что-то упустил? Или этот маршрут nhibernate просто перегружен?

В противном случае мне нравится чистота кода:

protected void Page_Load(object sender, EventArgs e)
{
    ICustomerRepository repository = new CustomerRepository();
    Customer customer = repository.GetById(id);
}

public class CustomerRepository : ICustomerRepository
        {
            public Customer GetById(string Id)
            {
                using (ISession session = NHibernateHelper.OpenSession())
                {
                    Customer customer = session
                                        .CreateCriteria(typeof(Customer))
                                        .Add(Restrictions.Eq("ID", Id))
                                        .UniqueResult<Customer>();
                    return customer;
                }
            }
        }

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

public class NHibernateHelper
    {
        private static ISessionFactory _sessionFactory;
        private static ISessionFactory SessionFactory
        {
            get
            {
                if (_sessionFactory == null)
                {
                    Configuration cfg = new Configuration();
                    cfg.Configure();
                    cfg.AddAssembly(typeof(Customer).Assembly);
                    _sessionFactory = cfg.BuildSessionFactory();
                }
                return _sessionFactory;
            }

        }

        public static ISession OpenSession()
        {
            return SessionFactory.OpenSession();
        }
    }

С приложением, над которым я работаю, скорость имеет значение. И, в конечном счете, много данных будет передаваться между веб-приложением и базой данных. Если агенту понадобится 1/3 секунды, чтобы восстановить запись о клиенте, а не 3 секунды, это будет большим успехом. Но если я делаю что-то странное, и это однократная первоначальная стоимость установки, то это может стоить того, чтобы производительность была такой же хорошей, как и выполнение хранимых процедур в БД.

Все еще открыты для предложений!


Обновлен.

Я отменяю свой маршрут ORM / NHibernate. Я обнаружил, что производительность слишком медленная, чтобы оправдать ее использование. Основные запросы клиентов просто слишком долго для нашей среды. 3 секунды по сравнению с ответами менее секунды слишком много.

Если бы мы хотели медленные запросы, мы бы просто сохранили нашу текущую реализацию. Идея переписать его состояла в том, чтобы резко увеличить время.

Однако, после игры с NHibernate на прошлой неделе, это отличный инструмент! Это просто не совсем соответствует моим потребностям в этом проекте.

Ответы [ 4 ]

6 голосов
/ 14 марта 2009

Если ваша конфигурация работает сейчас, зачем связываться с ней? Не похоже, что вы определяете какие-либо конкретные потребности или проблемы с кодом, как есть.

Я уверен, что куча ОО-типов могла бы собраться здесь и предложить различные рефакторинги здесь, чтобы уважать правильные обязанности и роли, и кто-то мог бы даже попытаться использовать один или два шаблона проектирования. Но код, который у вас есть сейчас, прост и звучит так, как будто у него нет проблем - я бы сказал, оставьте его.

5 голосов
/ 14 марта 2009

Я реализовал слой DAL, в основном делая то, что делает NHibernate, но вручную. NHibernate создает прокси-класс, который наследуется от вашего объекта Domain (все его поля должны быть помечены как виртуальные). Весь код доступа к данным переопределяет свойства, на самом деле это довольно элегантно.

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

public class Product {
  public int Id {get; set;}
  public int CustomerId { get; set;}
  public virtual Customer Customer { get; set;}
}
public class ProductLazyLoadProxy {
  ICustomerRepository _customerRepository;
  public ProductLazyLoadProxy(ICustomerRepository customerRepository) {
    _customerRepository = customerRepository;
  }
  public override Customer {
    get {
      if(base.Customer == null)
        Customer = _customerRepository.Get(CustomerId);
      return base.Customer
    }
    set { base.Customer = value; }
  }
}
public class ProductRepository : IProductRepository {
  public Product Get(int id) {
    var dr = GetDataReaderForId(id);
    return new ProductLazyLoadProxy() {
      Id = Convert.ToInt(dr["id"]),
      CustomerId = Convert.ToInt(dr["customer_id"]),
    }
  }
}

Но после написания около 20 из них я просто сдался и изучил NHibernate, с Linq2NHibernate для запросов и FluentNHibernate для конфигурации в настоящее время препятствия ниже, чем когда-либо.

2 голосов
/ 14 марта 2009

Скорее всего, в вашем приложении настроена логика домена в сценариях транзакций . Для реализаций .NET, использующих сценарий транзакции, Мартин Фаулер рекомендует использовать шаблон табличный шлюз данных . .NET обеспечивает хорошую поддержку этого шаблона, потому что шаблон шлюза табличных данных отлично подходит для набора записей , который Microsoft реализует с помощью своих классов типа DataSet.

Различные инструменты в среде Visual Studio должны повысить вашу производительность. Тот факт, что DataSets можно легко привязать к различным элементам управления (например, DataGridView), делает его хорошим выбором для приложений, управляемых данными.

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

2 голосов
/ 14 марта 2009

Это может быть слишком радикально для вас и на самом деле не решает вопрос, но как насчет полной утилизации вашего уровня данных и выбора ORM? Вы сэкономите много избыточного кода, что принесет потратить неделю или около того на DAL.

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

  • Объект службы в вашем классе электронной почты, скажем, EmailService, который создается в конструкторе или свойстве. Доступ через экземпляр, такой как email.Service.GetById (id)
  • Статический метод для электронной почты, такой как Email.GetById (id), который аналогичен
  • Полностью отдельный статический класс, который в основном является классом фасада, например EmailManager, со статическими методами, такими как EmailManager.GetById (int)
  • Шаблон ActiveRecord, где вы имеете дело с экземпляром, например email.Save () и email.GetById ()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...