Рейтинговые книги
Читем онлайн Язык программирования C#9 и платформа .NET5 - Эндрю Троелсен

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 256 257 258 259 260 261 262 263 264 ... 407
доступа к данным производственного уровня, то определенно пришлось бы использовать приемы структурированной обработки исключений (как объяснялось в главе 7), чтобы учесть любые аномалии времени выполнения.

Добавление реализации IDisposable

Добавьте к определению класса интерфейс IDisposable:

public class InventoryDal : IDisposable

{

  ...

}

Затем реализуйте шаблон освобождения, вызывая Dispose() на объекте SqlConnection:

bool _disposed = false;

protected virtual void Dispose(bool disposing)

{

  if (_disposed)

  {

    return;

  }

  if (disposing)

  {

    _sqlConnection.Dispose();

  }

  _disposed = true;

}

public void Dispose()

{

  Dispose(true);

  GC.SuppressFinalize(this);

}

Добавление методов выборки

Для начала объедините имеющиеся сведения об объектах команд, чтения данных и обобщенных коллекциях, чтобы получить записи из таблицы Inventory. Как было показано в начале главы, объект чтения данных в поставщике делает возможной выборку записей с использованием механизма, который реализует только чтение в прямом направлении с помощью метода Read(). В этом примере свойство CommandBehavior класса DataReader настроено на автоматическое закрытие подключения, когда закрывается объект чтения данных. Метод GetAllInventory() возвращает экземпляр List<CarViewModel>, представляющий все данные в таблице Inventory:

public List<CarViewModel> GetAllInventory()

{

  OpenConnection();

  // Здесь будут храниться записи.

  List<CarViewModel> inventory = new List<CarViewModel>();

  // Подготовить объект команды.

  string sql =

    @"SELECT i.Id, i.Color, i.PetName,m.Name as Make

          FROM Inventory i

          INNER JOIN Makes m on m.Id = i.MakeId";

  using SqlCommand command =

    new SqlCommand(sql, _sqlConnection)

    {

      CommandType = CommandType.Text

    };

  command.CommandType = CommandType.Text;

  SqlDataReader dataReader =

    command.ExecuteReader(CommandBehavior.CloseConnection);

  while (dataReader.Read())

  {

    inventory.Add(new CarViewModel

    {

      Id = (int)dataReader["Id"],

      Color = (string)dataReader["Color"],

      Make = (string)dataReader["Make"],

      PetName = (string)dataReader["PetName"]

    });

  }

  dataReader.Close();

  return inventory;

}

Следующий метод выборки получает одиночный объект CarViewModel на основе значения CarId:

public CarViewModel GetCar(int id)

{

  OpenConnection();

  CarViewModel car = null;

  // Параметры должны применяться по причинам, связанным с безопасностью.

  string sql =

   $@"SELECT i.Id, i.Color, i.PetName,m.Name as Make

          FROM Inventory i

          INNER JOIN Makes m on m.Id = i.MakeId

          WHERE i.Id = {id}";

  using SqlCommand command =

    new SqlCommand(sql, _sqlConnection)

    {

      CommandType = CommandType.Text

    };

  SqlDataReader dataReader =

    command.ExecuteReader(CommandBehavior.CloseConnection);

  while (dataReader.Read())

  {

    car = new CarViewModel

    {

      Id = (int) dataReader["Id"],

      Color = (string) dataReader["Color"],

      Make = (string) dataReader["Make"],

      PetName = (string) dataReader["PetName"]

    };

  }

  dataReader.Close();

  return car;

}

На заметку! Помещение пользовательского ввода внутрь низкоуровневых операторов SQL, как делалось здесь, обычно считается неудачной практикой. Позже в главе код будет модифицирован для использования параметров.

Вставка новой записи об автомобиле

Вставка новой записи в таблицу Inventory сводится к построению SQL-оператора Insert (на основе пользовательского ввода), открытию подключения, вызову метода ExecuteNonQuery() с применением объекта команды и закрытию подключения. Увидеть вставку в действии можно, добавив к типу InventoryDal открытый метод по имени InsertAuto(), который принимает три параметра, отображаемые на не связанные с идентичностью столбцы таблицы Inventory (Color, Make и PetName). Указанные аргументы используются при форматировании строки для вставки новой записи. И, наконец, для выполнения итогового оператора SQL применяется объект SqlConnection.

public void InsertAuto(string color, int makeId, string petName)

{

  OpenConnection();

  // Сформатировать и выполнить оператор SQL.

  string sql = $"Insert Into Inventory (MakeId, Color, PetName) Values ('{makeId}',

'{color}', '{petName}')";

  // Выполнить, используя наше подключение.

  using (SqlCommand command = new SqlCommand(sql, _sqlConnection))

  {

    command.CommandType = CommandType.Text;

    command.ExecuteNonQuery();

  }

  CloseConnection();

}

Приведенный выше метод принимает три значения для Car и работает при условии, что вызывающий код передает значения в правильном порядке. Более совершенный метод использует Car, чтобы стать строго типизированным, гарантируя тем самым, что все свойства передаются методу в корректном порядке.

Создание строго типизированного метода InsertCar()

Добавьте в класс InventoryDal еще одну версию метода InsertAuto(), которая принимает в качестве параметра Car:

public void InsertAuto(Car car)

{

  OpenConnection();

  // Сформатировать и выполнить оператор SQL.

  string sql = "Insert Into Inventory (MakeId, Color, PetName) Values " +

    $"('{car.MakeId}', '{car.Color}', '{car.PetName}')";

  // Выполнить, используя наше подключение.

  using (SqlCommand command = new SqlCommand(sql, _sqlConnection))

  {

    command.CommandType = CommandType.Text;

    command.ExecuteNonQuery();

  }

  CloseConnection();

}

Добавление логики удаления

Удаление существующей записи не сложнее вставки новой записи. В отличие от метода InsertAuto() на этот раз вы узнаете о важном блоке try/catch, который обрабатывает возможную попытку удалить запись об автомобиле, уже заказанном кем-то из таблицы Customers. Стандартные параметры INSERT и UPDATE для внешних ключей по умолчанию предотвращают удаление зависимых записей в связанных таблицах. Когда предпринимается попытка подобного удаления, генерируется исключение SqlException.

В реальной программе была бы предусмотрена логика обработки такой ошибки, но в рассматриваемом примере просто генерируется новое исключение. Добавьте в класс InventoryDal следующий метод:

public void DeleteCar(int id)

{

  OpenConnection();

  // Получить идентификатор автомобиля, подлежащего удалению,

  // и удалить запись о нем.

  string sql = $"Delete from

1 ... 256 257 258 259 260 261 262 263 264 ... 407
На этой странице вы можете бесплатно читать книгу Язык программирования C#9 и платформа .NET5 - Эндрю Троелсен бесплатно.

Оставить комментарий