Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/http/4.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#和SQL Server Express以及DataGridView在插入表后更新_C#_Sql Server_Winforms_Datagridview - Fatal编程技术网

C#和SQL Server Express以及DataGridView在插入表后更新

C#和SQL Server Express以及DataGridView在插入表后更新,c#,sql-server,winforms,datagridview,C#,Sql Server,Winforms,Datagridview,我不熟悉SQL Server数据库,我在Winforms应用程序中有一个简单的datagridview。datagridview绑定到SQL Server数据库 我需要在按下按钮时更新datagridview和后端数据库 private void btnAdd_Click(object sender, EventArgs e) { var str = txtNewSource.Text; var data = this.tBL_SourceTableAdapter.GetDa

我不熟悉SQL Server数据库,我在Winforms应用程序中有一个简单的datagridview。datagridview绑定到SQL Server数据库

我需要在按下按钮时更新datagridview和后端数据库

private void btnAdd_Click(object sender, EventArgs e)
{
     var str = txtNewSource.Text;
     var data = this.tBL_SourceTableAdapter.GetData();
     var length = data.Rows.Count;
     this.tBL_SourceTableAdapter.Insert(length + 1, str);
     sourceDataGridView.refresh(); // This does not refresh the data in the form!
 }
我想用刚刚添加到数据库中的新数据更新绑定的datagridview。我可以看到数据被添加到数据库中。如果使用datagridview关闭窗口并重新打开,则新添加的值可见

插入绑定数据库表后,如何刷新datagridview中的数据

我对其他能达到预期效果的方法持开放态度。我不允许用户编辑datagridview中的值,因为不是表中的所有列都对用户可见,而且我需要保持索引的正确顺序

我尝试过的事情:

我试图在gridview中添加新行,如下所示:

sourceDataGridView.rows.add(); // I get a runtime error cannot add row to bound datagrid.
sourceDataGridView.rows[n].cells[0].value = str; 
我试图在datagrid上重置数据源,但也没有成功


谢谢。

您不能用这种方式刷新网格视图。您必须清除现有数据网格中的行,并将其与数据源重新绑定

您不能以这种方式刷新网格视图。您必须清除现有数据网格中的行,并将其与数据源重新绑定

将数据与其显示方式分开 在现代编程中,有一种倾向是将数据(模型)与向操作员(视图)显示数据的方式分开

这使您可以自由更改显示,而无需更改模型。例如,如果您希望显示较少的列,或者希望以不同的颜色显示负数,或者希望在Excel工作表中显示负数

类似地,您可以更改模型而不必更改视图:如果您希望从CSV文件或Json而不是数据库获取数据,或者甚至可能从internet获取数据:您不希望更改基于此数据创建的视图

通常,您需要一个适配器使模型适合显示器。此适配器通常称为ViewModel。这三个项目一起缩写为MVVM。考虑阅读一些关于这方面的背景信息。

分离模型和视图后,您将拥有以下方法:

  • 从存储库获取数据。存储库是您的数据库,但它可以是任何内容:CSV?Json、XML、internet,或者只是用于单元测试的字典
  • 将数据写入存储库
  • 显示数据
  • 获取编辑的数据
也许您需要一种方法来找出哪些已编辑的数据已更改,因此需要在存储库中进行更新

您写道您是SQL Server数据库的新手。如果我看一下你剩下的问题,似乎读写数据库不是你的问题。因此,我不会深入讨论这个问题。我将首先介绍如何使用普通的SQL和DbReaders访问数据库。如果你已经知道怎么做了,你可以跳过这一章

之后,我将解释如何显示获取的数据

访问数据库 您是使用普通的旧SQL获取数据,还是使用实体框架?因为您将其隐藏在存储库中,这对外部世界并不重要。如果您改变获取和更新数据的方式,它不会改变

遗憾的是,您忘记了写入DataGridView中显示的内容以及数据库中的内容。因此,我必须给你举个例子

假设您要显示产品:几个恒定的产品属性:名称、描述、产品代码,以及价格和库存商品数量

class Product
{
     public int Id {get; set;}
     public string ProductCode {get; set;}
     public string Name {get; set;}
     public string Description {get; set;}

     public decimal Price {get; set;}
     public int StockCount {get; set;}
}


interface IRepository
{
    IEnumerable<Product> FetchProductsToDisplay(...);
    void UpdateProducts(IEnumerable<Product> product);
}

class Repository : IRepository
{
   // TODO: implement
}
确切的SQL文本因您使用的每个数据库管理系统而异。例如,
SQLight
使用
Limit 30
而不是
TOP 30

幸运的是,您将模型与视图分离,并将这些详细信息隐藏在存储库类中,因此,如果您决定使用其他方法访问数据库,则存储库之外的内容不会发生任何更改

您可能还需要一个左外部联接、GroupBy、Where、Order等。确切的SQL有点超出了问题的范围

重要的是要记住,使用运算符或其他外部源可能提供的输入值更改SQL字符串是非常危险的。如果你从未听说过,请阅读

始终将SQL设置为常量字符串。使用变量插入运算符输入

例如,如果您只想在特定仓库位置显示产品:

const string sqlTextFetchProducts = @"SELECT ... FROM Products;";
    + @" WHERE WareHouseLocationId = @WareHouseLocationId"
好的,让我们实现FetchProductsToDisplay:

private string DbConnectionString => ...; // gets the database connection string

IEnumerable<Product> FetchProductsToDisplay(int wareHouseLocationId);
{
    const string sqlTextFetchProducts = @"...;";

    using (var dbConnection = new SQLiteConnection(this.DbConnectionString))
    {
        using (var dbCommand = dbConnection.CreateCommand())
        {
            dbCommand.CommandText = sqlTextFetchProducts ;
            dbCommand.Parameters.AddWithValue("@WareHouseLocationId", wareHouseLocationId);
            dbConnection.Open();

            // Execute the query and returns products one by one
            using (SQLiteDataReader dbReader = dbCommand.ExecuteReader())
            {
                while (dbReader.Read())
                {
                    Product fetchedProduct = new Product
                    {
                        Id = dbReader.GetInt64(0),
                        ProductCode = dbReader.GetString(1),
                        ...
                        Price = dbReader.GetDecimal(4),
                        StockCount = dbReader.GetInt32(5),
                    };
                    yield return fetchedProduct;
                }
            }
        }
    }
}
为此创建一个特殊的SQL可能更有效,但是对于这个示例,您可以看到,您不需要将所有获取的数据转换为产品

使用参数

SQL文本是常量。参数有一个前缀
@
,用于将其与文字文本区分开来。这仅仅是惯例,您可以更改它,但这样可以很容易地发现参数

参数值将逐个添加,例如,如果您只希望产品位于WareHouseLocation 10,库存数量至少为2,最高价格为25欧元,则可以更改SQL,使其包含
@WareHouseLocation、@StockCount、@price
,然后添加:

IEnumerable<Product> FetchProductsToDisplay(
    int wareHouseLocationId,
    int minimumStockCount,
    decimal maximumPrice)
{
    using(...)
    ...

   dbCommand.Parameters.AddWithValue("@WareHouseLocationId", wareHouseLocationId);
dbCommand.Parameters.AddWithValue("@StockCount", minimumStockCount);
dbCommand.Parameters.AddWithValue("@Price", maximumPrice);
...
只要存在未读的回迁数据,则返回true

Id = dbReader.GetInt64(0),
ProductCode = dbReader.GetString(1),
...
SQL文本
中提取的项选择Id、ProductCode。。。从…
有索引,Id有索引0,ProductCode有索引1,等等。使用适当的
dbReader。获取…
将获取的项目转换为适当的类型

将dbReader中获取的数据转换为类的确切方法可能因数据库管理系统而异,但我想您会明白要点

当然,您还需要一种方法来更新产品。这如果相当相似,,
IEnumerable<Product> FetchProductsToDisplay(
    int wareHouseLocationId,
    int minimumStockCount,
    decimal maximumPrice)
{
    using(...)
    ...

   dbCommand.Parameters.AddWithValue("@WareHouseLocationId", wareHouseLocationId);
dbCommand.Parameters.AddWithValue("@StockCount", minimumStockCount);
dbCommand.Parameters.AddWithValue("@Price", maximumPrice);
...
while (dbReader.Read())
Id = dbReader.GetInt64(0),
ProductCode = dbReader.GetString(1),
...
public void UpdateProductPrice(int productId, decimal price)
{
    const string sqlText = "UPDATE " + tableNameProducts
        + " SET Price = @Price"
        + " WHERE Id = @Id;";

    using (SQLiteCommand dbCommand = this.DbConnection.CreateCommand())
    {
        dbCommand.CommandText = sqlText;
        dbCommand.Parameters.AddWithValue("@Id", productId);
        dbCommand.Parameters.AddWithValue("@Price", productPrice);
        dbCommand.ExecuteNonQuery();
    }
}
public MyForm()
{
    InitializeComponent();

    this.columnProductId.DataPropertyName = nameof(Product.Id);
    this.columnProductName.DataPropertyName = nameof(Product.Name);
    ...
    this.columnProductPrice.DataPropertyName = nameof(Product.Price);
}
private BindingList<Product> DisplayedProducts
{
    get => (BindingList<Product>) this.dataGridViewProducts.DataSource,
    set => this.dataGridViewProducts.DataSource = value;
}
private IRepository Repository {get;} = new Repository();

private IEnumerable<Product> FetchProductsToDisplay()
{
    return this.Repository.FetchProductsToDisplay(...);
}

public void InitProductDisplay()
{
    this.DisplayedProducts = new BindingList<Product>(
        this.FetchProductsToDisplay().ToList());
}
private void OnButtonApplyNow_Clicked(object sender, ...)
{
    Collection<Product> editedProducts = this.Displayedproducts();

    // find out which Products are changed and save them in the repository
    this.ProcessEditedProducts(editedProducts);
}