Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/281.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在简单的WinForms应用程序中管理数据访问_C#_Winforms_Sqlite_Datatable_Sqlconnection - Fatal编程技术网

C# 在简单的WinForms应用程序中管理数据访问

C# 在简单的WinForms应用程序中管理数据访问,c#,winforms,sqlite,datatable,sqlconnection,C#,Winforms,Sqlite,Datatable,Sqlconnection,我有一个简单的WinForms数据输入应用程序,它使用SQLite。它将始终是一个单用户应用程序,并且始终带有本地数据库。我有多个选项卡,用户控件作为选项卡的内容。每次选择一个选项卡时,都会初始化相应的UserControl,并删除旧的一个(使用TabPage.Controls.Remove) 每个UserControl初始化一个通用DataAccess对象,该对象包装所有数据库内容,并可与任何选项卡内容一起重用。问题是,在选项卡(UserControl)的生命周期内,我有一个打开的SQLite

我有一个简单的WinForms数据输入应用程序,它使用SQLite。它将始终是一个单用户应用程序,并且始终带有本地数据库。我有多个选项卡,用户控件作为选项卡的内容。每次选择一个选项卡时,都会初始化相应的UserControl,并删除旧的一个(使用TabPage.Controls.Remove)

每个UserControl初始化一个通用DataAccess对象,该对象包装所有数据库内容,并可与任何选项卡内容一起重用。问题是,在选项卡(UserControl)的生命周期内,我有一个打开的SQLiteConnection。我在别处读到过,这不是一个好的做法。我不想过度使用精心设计的数据层和业务对象层,部分原因是我不知道怎么做,部分原因是我认为这个应用程序没有必要这样做

我基本上在内存中保留相同的连接、适配器、DataTable、SqlCommand等对象,并使用不同的sql查询参数重用它们,并使用其他方法(如RowCount)获取缓存数据。我对LoadData方法有一个问题,因为它没有从DataTable中清除以前的查询结果,所以我在开始时手动执行

我试图找到一种方法来使用SQLiteConnection和其他对象的“using”,但是对于RowCount等简单的事情,我必须重做整个DataLoad或类似的东西。所以我只是在寻找关于这种数据访问方法的建议和评论

下面是我的DataAccess类

public class DataAccess
{
    private SQLiteConnection connection = new SQLiteConnection(Global.DbConnectionString);
    private DataTable dataTable = new DataTable();
    private SQLiteDataAdapter dataAdapter = new SQLiteDataAdapter();
    private SQLiteCommandBuilder commandBuilder = new SQLiteCommandBuilder();
    private SQLiteCommand command = new SQLiteCommand();
    private BindingSource bindingSource = new BindingSource();


    public DataAccess()
    {
        dataAdapter.SelectCommand = command;
        commandBuilder.DataAdapter = dataAdapter;
        bindingSource.DataSource = dataTable;
    }

    ~DataAccess()
    {
        connection.Dispose();
    }

    public BindingSource BindingSource
    {
        get { return bindingSource; }
    }


    ///*
    public void LoadData(string sql, Dictionary<string, string> parameters)
    {
        try
        {
            dataTable.Clear();
            command.Connection = connection;

            // Ignore sql parameter if we already have CommandText. This assumes sql never changes per instance
            if (command.CommandText == null)
                command.CommandText = sql;

            foreach (KeyValuePair<string, string> parameter in parameters)
            {
                if (command.Parameters.Contains(parameter.Key))
                    command.Parameters[parameter.Key].Value = parameter.Value;
                else
                {
                    command.Parameters.Add(new SQLiteParameter(parameter.Key));
                    command.Parameters[parameter.Key].Value = parameter.Value;
                }
            }
            dataAdapter.Fill(dataTable);

        }
        catch (SqlException)
        {
            MessageBox.Show("Data Problem, need to display what's wrong later");
        }

    }//*/

    public int RowCount()
    {
        return dataTable.Rows.Count;
    }

    public string GetFieldValue(int row_index, string column_name)
    {
        return dataTable.Rows[row_index][column_name].ToString();
    }

    public void Save()
    {
        dataAdapter.Update(dataTable);
    }

    public void NewRow(Dictionary<string, string> fields)
    {
       DataRow dataRow = dataTable.NewRow();

        foreach (KeyValuePair<string, string> field in fields)
            dataRow[field.Key] = field.Value;

        dataTable.Rows.Add(dataRow);
    }
}
公共类数据访问
{
私有SQLiteConnection=newsqliteconnection(Global.DbConnectionString);
私有数据表=新数据表();
私有SQLiteDataAdapter dataAdapter=新的SQLiteDataAdapter();
私有SQLiteCommandBuilder commandBuilder=新SQLiteCommandBuilder();
private SQLiteCommand=new SQLiteCommand();
私有BindingSource BindingSource=新BindingSource();
公共数据访问()
{
dataAdapter.SelectCommand=命令;
commandBuilder.DataAdapter=数据适配器;
bindingSource.DataSource=dataTable;
}
~DataAccess()
{
connection.Dispose();
}
公共绑定源绑定源
{
获取{return bindingSource;}
}
///*
公共void加载数据(字符串sql、字典参数)
{
尝试
{
dataTable.Clear();
command.Connection=连接;
//如果已经有CommandText,则忽略sql参数。这假定每个实例的sql从不更改
if(command.CommandText==null)
command.CommandText=sql;
foreach(参数中的KeyValuePair参数)
{
if(command.Parameters.Contains(parameter.Key))
command.Parameters[parameter.Key].Value=parameter.Value;
其他的
{
添加(新的SQLiteParameter(parameter.Key));
command.Parameters[parameter.Key].Value=parameter.Value;
}
}
dataAdapter.Fill(dataTable);
}
捕获(SqlException)
{
Show(“数据问题,需要稍后显示错误”);
}
}//*/
公共整数行计数()
{
返回dataTable.Rows.Count;
}
公共字符串GetFieldValue(int行索引、字符串列名称)
{
返回dataTable.Rows[行索引][列名称].ToString();
}
公共作废保存()
{
dataAdapter.Update(dataTable);
}
public void NewRow(字典字段)
{
DataRow DataRow=dataTable.NewRow();
foreach(字段中的KeyValuePair字段)
dataRow[field.Key]=field.Value;
dataTable.Rows.Add(dataRow);
}
}

如果您想做得更好,应该创建一个数据访问层,该层将公开获取数据和修改数据的方法。该层将在必要时打开连接,然后关闭它。您可以在上面添加一个缓存层。您的GUI将只使用较低层的数据对象


这不是一个小的重写,所以如果您当前的解决方案有效,并且您不想在其中投入太多精力,那么就让它保持这样,它并没有那么糟糕。如果它是一个简单的程序,那么这个简单的解决方案就很好。

有了这个设计,你能对你的应用程序进行单元测试吗?不,甚至还没有考虑过单元测试。谢谢,你知道我可以看的这类应用程序的任何例子吗?