Литмир - Электронная Библиотека

}

public interface IOrderService {

  IOrder Create(ICustomer customer, IProduct product, int count,

      DateTime orderDateTime);

  void Delete(IOrder order);

  void Update(IOrder order, ICustomer customer,

      IProduct product, int count, DateTime orderDateTime);

}

public interface IProductService {

  IProduct Create(string name, bool isAvailable, decimal cost);

  void Delete(IProduct product);

  void Update(IProduct product, string name,

          bool isAvailable, decimal cost);

Реализуем интерфейсы сервисов, как показано в листинге 3.4, для класса customerService. Чтобы уменьшить количество кода, приводить реализацию для других классов мы не будем, для остальных классов определяем методы Create, Delete и Update точно таким же образом.

Листинг 3.4. Реализация интерфейсов сервисов

public class CustomerService : ICustomerService {

  private readonly MyDatabaseDataContext _database;

  public CustomerService(MyDatabaseDataContext db)

  {

    if (db == null)

      throw new ArgumentNullException("db");

    _database = db;

  }

  public ICustomer Create(string name, string phone, string address)

  {

    if (String.IsNullOrEmpty(name))

      throw new ArgumentNullException("name");

    Customer customer = new Customer()

             {

               CustomerId = Guid.NewGuid(),

               Address = address,

               Phone = phone,

               Name = name

             };

    _database.Customers.InsertOnSubmit(customer);

    return customer;

  }

  public void Delete(ICustomer customer)

  {

    if (customer == null)

      throw new ArgumentNullException("customer");

    _database.Customers.DeleteOnSubmit((Customer)customer);

  }

  public void Update(ICustomer customer, string name,

                     string phone, string address)

  {

    if (customer == null)

      throw new ArgumentNullException("customer");

    if (String.IsNullOrEmpty(name))

      throw new ArgumentNullException("name");

    customer.Name = name;

    customer.Phone = phone;

    customer.Address = address;

  }

}

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

public class UnitOfWork : IDisposable {

  private readonly MyDatabaseDataContext _database;

  public MyDatabaseDataContext DataContext {

    get

    {

      return _database;

    }

  }

  private bool _disposed;

  public UnitOfWork()

  {

    _database = new MyDatabaseDataContext();

  }

  public void Commit()

  {

    _database.SubmitChanges();

  }

  public void Dispose()

  {

    Dispose(true); GC.SuppressFinalize(this);

  }

  private void Dispose(bool disposing) {

    if (!this._disposed)

    {

      if (disposing)

      {

        _database.Dispose();

      }

      _disposed = true;

    }

  }

}

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

Пример использования слоя данных

Наша инъекция кода полностью реализована, рассмотрим вариант использования:

using (UnitOfWork unitOfWork = new UnitOfWork())

{

  ICustomerService customerService = new

    CustomerService(unitOfWork.DataContext);

  IOrderService orderService = new

    OrderService(unitOfWork.DataContext);

  IProductService productService = new

    ProductService(unitOfWork.DataContext);

  ICustomer customer = customerService.Create("Hoвый заказчик",

        "111-22-33", "Адрес нового заказчика");

  IProduct product = productService.Create("Новый товар", true, 50000);

  orderService.Create(customer, product, 200, DateTime.Now);

  unitOfWork.Commit();

}

Обратите внимание, в приведенном коде нет ни одной зависимости, которая привязывала бы нас либо к конкретной базе данных, либо к конкретному механизму ORM. Для замены одного из этих элементов нам потребуется всего лишь реализовать служебные механизмы вроде класса unitofWork, хранилищ и сервисов, согласно требованиям, но не приведенный код. Любой код, написанный с использованием описанных ранее механизмов, не потребует модернизации.

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

Механизмы для работы с данными

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

XML-данные

.NET Framework предлагает широкий ассортимент объектов для доступа к XML-данным, которые расположены в стандартных сборках: System.Xml, System.Xml.XPath, System.Xml.Xsl, System.Xml.Schema и System.Xml.Linq. Рассмотрим назначение и наиболее полезные классы каждой из сборок:

□ System.Xml — содержит базовые классы для работы с XML, такие как

XmlDocument, XmlElement, XmlNode и множество других, которые позволяют реализовать загрузку из файлов, обработку, добавление, изменение, удаление XML-данных;

□ System.Xml.XPath — содержит классы для реализации работы механизма XPath, позволяющего писать выражения к XML-документу для поиска необходимых данных;

□ System.Xml.Xsl — содержит классы для поддержки реализации XSLT-преобразований XML-документа;

□ System.Xml.Schema — содержит классы для поддержки XSD-схем и валидации XML-данных на их основе. Содержит большое число классов, позволяющих создавать XSD-схемы и использовать их;

□ System.Xml.Lin —  последняя сборка, которая недавно появилась в .NET Framework. Содержит классы, реализующие механизм доступа к XML-данным на основе LINQ-выражений. Этот механизм носит собственное название LINQ для XML. Он позволяет использовать уже известные вам LINQ-выражения для обработки XML-данных.

Рассмотрим пример обработки XML-данных с помощью LINQ для XML. Предположим, что у нас есть следующий XML-файл:

<?xml version="1.0"?>

15
{"b":"971383","o":1}