如何使用SQLiteDataAdapter读取混合数据类型?

时间:2018-10-24 14:56:17

标签: c# sqlite

我正在尝试制作一个C#GUI来编辑SQLite数据库。当我使用SQLiteDataAdapter填充DataGridView时,数据显示不正确:

  1. 存储在数字字段中的字符串显示为0。
  2. 存储在整数字段中的实数取整(即6.54显示为6)。

SQLiteDataAdapter错误地加载了数据,因此数据在到达演示者时就不正确。有关SQLite数据类型的信息,请参见this

这是我在演示者中加载表格的代码(我遵循带有被动视图的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立即将所有值从数据库转换为该列的声明的相似性类型。
  • 错误地加载了数据之后,遍历所有列,并手动重新加载/更正具有麻烦的列类型(int和数字)的列中的每个条目。我为此使用SQLiteDataReader,代码变得非常复杂和缓慢。

由于复杂性,我曾经尝试过但尚未尝试实现的另一个想法:

  • 使用SQLiteDataReader手动加载行,可能使用虚拟模式进行即时加载(请参见this MSDN文章)。

我担心这最后一个选项会创建复杂的代码并导致过滤问题。我的客户希望能够快速将过滤器应用于表格。现在,我正在使用BindingSource进行过滤,与将查询发送到SQLite相比,这是非常快的。

我是否缺少某些东西或是否没有优雅的方法来处理C#中混合类型的SQLite数据库?我已经花了数小时搜寻网路,却找不到任何有类似问题的人。

编辑:我应该补充一点,我正在使用System.Data.SQLite。

1 个答案:

答案 0 :(得分:0)

这不是很漂亮,但是对于那些感兴趣的人,我想出了一种解决方法。

这是从数据库中初始加载后调用的 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);
        }
    }
}

以下是模型中查询数据库的方法:

    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;
    }

再次,这确实是一种解决方法,对于那些制作消费者级应用程序的人(我只是在开发工具),这不是一个干净的解决方案。