Предложите Visual Studio или Visual Studio Code самостоятельно реализовать все методы (либо скопировать их), что даст вам отправную точку для специального класса чтения данных. В рассматриваемом сценарии потребуется реализовать лишь члены, кратко описанные в табл. 21.7.

Начните с метода Read(), который возвращает false, если класс для чтения находится в конце списка, или true (с инкрементированием счетчика уровня класса), если конец списка еще не достигнут. Добавьте переменную уровня класса, которая будет хранить текущий индекс List, и обновите метод Read(), как показано ниже:

public class MyDataReader : IMyDataReader

{

  ...

  private int _currentIndex = -1;

  public bool Read()

  {

    if (_currentIndex + 1 >= Records.Count)

    {

      return false;

    }

    _currentIndex++;

    return true;

  }

}

Каждый метод GetXXX() и свойство FieldCount требуют знания специфической модели, подлежащей загрузке. Вот как выглядит метод GetValue(), использующий CarViewModel:

public object GetValue(int i)

{

  Car currentRecord = Records[_currentIndex] as Car;

  return i switch

  {

    0 => currentRecord.Id,

    1 => currentRecord.MakeId,

    2 => currentRecord.Color,

    3 => currentRecord.PetName,

    4 => currentRecord.TimeStamp,

    _ => string.Empty,

  };

}

База данных содержит только четыре таблицы, но это означает необходимость в наличии четырех вариаций класса чтения данных. А подумайте о реальной производственной базе данных, в которой таблиц гораздо больше!Решить проблему можно более эффективно с применением рефлексии (см. главу 17) и LINQ to Objects (см. главу 13).

Добавьте переменные readonly для хранения значений PropertyInfo модели и словарь, который будет использоваться для хранения местоположения поля и имени таблицы в SQL Server. Модифицируйте конструктор, чтобы он принимал свойства обобщенного типа и инициализировал объект Dictionary. Ниже показан добавленный код:

private readonly PropertyInfo[] _propertyInfos;

private readonly Dictionary _nameDictionary;

public MyDataReader(List records)

{

  Records = records;

  _propertyInfos = typeof(T).GetProperties();

  _nameDictionary = new Dictionary();

}

Модифицируйте конструктор, чтобы он принимал строку подключения SQLConnection, а также строки для имен схемы и таблицы, куда будут вставлены записи, и добавьте для этих значений переменные уровня класса:

private readonly SqlConnection _connection;

private readonly string _schema;

private readonly string _tableName;

public MyDataReader(List records, SqlConnection connection,

                    string schema, string tableName)

{

  Records = records;

  _propertyInfos = typeof(T).GetProperties();

  _nameDictionary = new Dictionary();

  _connection = connection;

  _schema = schema;

  _tableName = tableName;

}

Далее реализуйте метод GetSchemaTable(), который извлекает информацию SQL Server, касающуюся целевой таблицы:

public DataTable GetSchemaTable()

{

  using var schemaCommand =

    new SqlCommand($"SELECT * FROM {_schema}.{_tableName}", _connection);

  using var reader = schemaCommand.ExecuteReader(CommandBehavior.SchemaOnly);

  return reader.GetSchemaTable();

}

Модифицируйте конструктор, чтобы использовать SchemaTable для создания словаря, который содержит поля целевой таблицы в порядке их следования внутри базы данных:

public MyDataReader(List records, SqlConnection connection,

                    string schema, string tableName)

{

  ...

  DataTable schemaTable = GetSchemaTable();

  for (int x = 0; x

  {

    DataRow col = schemaTable.Rows[x];

    var columnName = col.Field("ColumnName");

    _nameDictionary.Add(x,columnName);

  }

}

Перейти на страницу:

Похожие книги