Как читать смешанные типы данных с помощью SQLiteDataAdapter? - PullRequest
0 голосов
/ 24 октября 2018

Я пытаюсь сделать C # GUI для редактирования базы данных SQLite.Когда я заполняю свой DataGridView с помощью SQLiteDataAdapter, данные отображаются неправильно:

  1. Строки, хранящиеся в числовом поле, отображаются как 0.
  2. Реалы, сохраненные в целочисленном поле, получают этажзаземлен (т. е. 6,54 отображается как 6).

Данные загружаются некорректно SQLiteDataAdapter , поэтому данные неверны в момент их поступления к докладчику.См. this для получения информации о типах данных SQLite.

Вот мой код для загрузки таблицы в презентере (я следую шаблону проектирования MVP с пассивным представлением):

//Presenter method    
private void BindData()
{
    DataTable entireTable = _model.GetEntireTable(GetTableName());
    //_screen is the View (actual form) of the program
    //_screen.MainTableDataSource is a BindingSource
    //_screen.MainTable is a DataGridView
    _screen.MainTableDataSource.DataSource = entireTable;
    _screen.MainTable.DataSource = _screen.MainTableDataSource;
}

//Model method
public DataTable GetEntireTable(string tableName)
{
    string query = "SELECT rowid, * FROM " + tableName;
    _dataAdapter = new SQLiteDataAdapter(query, _connection);
    _dt = new DataTable();
    _dataAdapter.Fill(_dt);
    return _dt;
}

Решения, которые я до сих пор пробовал:

  • Заставить клиента разрешить мне применять строгие столбцы.В базе данных уже были десятки столбцов со смешанными типами данных с ценными сценариями использования, поэтому в конечном итоге это не вариант.
  • Преобразование всех типов значений DataGridViewColumn в строки.Проблема заключается в том, что DataAdapter немедленно преобразует все значения в объявленный тип сходства столбца из базы данных.
  • После того, как данные были загружены неправильно, выполните итерацию по всем столбцам и вручную перезагрузите / исправьте каждую запись в столбцах с проблемами.типы столбцов (целые и числовые).Я использую SQLiteDataReader для этого, и код становится очень сложным и медленным.

Еще одна идея, которую я имел, но не пытался реализовать из-за сложности:

  • Вручную загружать строки с использованием SQLiteDataReader, возможно, с своевременной загрузкой в ​​виртуальном режиме (см. эту статью MSDN).

Я беспокоюсь, что последний вариант будетсоздать сложный код и вызвать проблемы с фильтрацией.Мой клиент хочет иметь возможность быстро применять фильтры к таблицам.Прямо сейчас я использую BindingSource для фильтрации, что очень быстро по сравнению с отправкой запросов в SQLite.

Я что-то упустил или не существует элегантного способа обработки баз данных SQLite со смешанными типами в C # ?Я часами искал в интернете и не могу найти никого с подобной проблемой.

Редактировать: я должен добавить, что я использую System.Data.SQLite.

1 Ответ

0 голосов
/ 24 октября 2018

Это не красиво, но для тех, кто заинтересован, я нашел обходной путь.

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

//Presenter method called after initial load from database
private void CheckDataBaseForWrongTypes(string table)
{
    foreach (DataGridViewColumn col in _table.Columns)
    {
        col.ValueType = typeof(string);
    }
    DataTable typeCheckerDT = _model.GetSchemaForCurrentTable(table);
    int i = -1;
    foreach (DataRow row in typeCheckerDT.Rows)
    {
        i++;
        string col = Convert.ToString(row.ItemArray[1]);
        string type = Convert.ToString(row.ItemArray[2]);
        if (type.Equals("TEXT") || type.Equals("BLOB")) //Columns of this type will always display correctly, as far as I know
        {
            continue;
        }
        //Correct values in numeric field that are actually stored as strings in database
        DataTable invalidTable = _model.GetNonNumericDataInSpecifiedColumn(table, col);
        DataTable dt = _model.GetMainTableDT();
        dt.PrimaryKey = new DataColumn[] { dt.Columns["rowid"] };
        foreach (DataRow invalidRow in invalidTable.Rows)
        {
            int rowPrimaryKey = Convert.ToInt32(invalidRow.ItemArray[0]);
            DataRow rowToModifyType = dt.Rows.Find(rowPrimaryKey);
            int index = dt.Rows.IndexOf(rowToModifyType);
            _table.Rows[index].Cells[i + 1].Value = _model.GetActualDataBaseStringValueInANumericColumn(_table.Name, rowPrimaryKey, col);
        }
        if (type.Equals("REAL") || type.Equals("NUMERIC")) //Decimals will only be displayed incorrectly in integer columns
        {
            continue;
        }
        //Correct values in integer field that are actually decimals
        invalidTable = _model.GetDecimalDataInSpecifiedColumn(table, col);
        dt = _model.GetMainTableDT();
        dt.PrimaryKey = new DataColumn[] { dt.Columns["rowid"] };
        foreach (DataRow invalidRow in invalidTable.Rows)
        {
            int rowPrimaryKey = Convert.ToInt32(invalidRow.ItemArray[0]);
            DataRow rowToModifyType = dt.Rows.Find(rowPrimaryKey);
            int index = dt.Rows.IndexOf(rowToModifyType);
            _table.Rows[index].Cells[i + 1].Value = _model.GetActualDataBaseRealValueInAnIntegerColumn(_table.Name, rowPrimaryKey, col);
        }
    }
}

Вот методы из Model , запрашивающие базу данных:

    public DataTable GetNonNumericDataInSpecifiedColumn(string table, string col)
    {
        string query = "SELECT rowid, * FROM " + table + " WHERE [" + col + "] GLOB '*[^0123456789.-]*'";
        return FetchDTFromDatabase(query);
    }

    public DataTable GetDecimalDataInSpecifiedColumn(string table, string col)
    {
        string query = "SELECT rowid, * FROM " + table + " WHERE [" + col + "] NOT GLOB '*[a-zA-Z]*' AND [" + col + "] GLOB '*.*';";
        return FetchDTFromDatabase(query);
    }

    public string GetActualDataBaseStringValueInANumericColumn(string table, int rowPrimaryKey, string colName)
    {
        string query = "SELECT [" + colName + "] FROM " + table + " WHERE rowid=" + rowPrimaryKey + ";";
        using (SQLiteCommand cmd = new SQLiteCommand(query, _connection))
        {
            using (SQLiteDataReader reader = cmd.ExecuteReader())
            {
                reader.Read();
                string value = reader.GetString(0);
                return value;
            }
        }
    }

    public string GetActualDataBaseRealValueInAnIntegerColumn(string table, int rowPrimaryKey, string colName)
    {
        string query = "SELECT [" + colName + "] FROM " + table + " WHERE rowid=" + rowPrimaryKey + ";";
        using (SQLiteCommand cmd = new SQLiteCommand(query, _connection))
        {
            using (SQLiteDataReader reader = cmd.ExecuteReader())
            {
                reader.Read();
                double value = reader.GetDouble(0);
                return value.ToString();
            }
        }
    }

    private DataTable FetchDTFromDatabase(string query)
    {
        SQLiteDataAdapter adapter = new SQLiteDataAdapter(query, _connection);
        DataTable table = new DataTable();
        adapter.Fill(table);
        return table;
    }

Опять же, это действительно обходной путь, и он не будет чистым решением для тех, кто делает на уровне потребителяприложение (я просто делаю инструмент разработки).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...