繁体   English   中英

C# 如何从 SQL 数据表中删除 datagridview SelectedRows

[英]C# How to delete datagridview SelectedRows from SQL datatable

我有一个数据绑定数据网格视图和一些按钮,用于从 SQL 数据表中编辑、添加、删除数据。 我的主要目标是制作一个按钮,用于从用户选择的数据表中删除 SelectedRows。

由于我只需要来自第一列的数据,因此我的 Column.Index 将始终为 0

现在,从用户选择的行中,我将 Row.Index 保存在一个数组中,这样我就可以查明并删除之后选择的行所在的行。 问题是我不能在 foreach 循环之外使用我的 SelectedRowIndexes 数组,因为它是一个局部变量。 例如,当我运行 Console.WriteLine 命令时,我收到我的数组在当前上下文中不存在的错误。 我想错了吗? 有一些解决方法吗?

private void BtnRemoveClick(object sender, System.EventArgs e)
{
    foreach (DataGridViewRow row in datagridview1.SelectedRows)
    {
        int[] SelectedRowIndexes = { row.Index };
    }


    for (int i=0; i<SelectedRowIndexes.Length; i++)
    {
        Console.WriteLine(SelectedRowIndexes[i]); // error CS0103: The name 'SelectedRowIndexes' does not exist in the current context
    }
}

如果您的网格绑定到DataTable ,则每行的DataBoundItem都是DataRowView 您可以使用循环或 LINQ 查询将网格的SelectedRows中的每一个获取到数组或集合中,在每个上调用Delete ,然后在数据适配器上调用Update以保存所有更改。 例如

var rows = myDataGridView.SelectedRows
                         .Cast<DataGridViewRow>()
                         .Select(dgvr => dgvr.DataBoundItem)
                         .Cast<DataRowView>()
                         .ToArray();

foreach (var row in rows)
{
    row.Delete();
}

myDataAdapter.Update(myDataTable);

这假定myDataTable绑定到myDataGridView并且myDataAdapter已配置适当的DeleteCommand

如果您已经通过BindingSource绑定了DataTable ,那么您也可以通过其他方式进行绑定:

var rowIndexes = myDataGridView.SelectedRows
                               .Cast<DataGridViewRow>()
                               .Select(dgvr => dgvr.Index)
                               .ToArray();

for (var i = rowIndexes.GetUpperBound(0); i >= 0; i--)
{
    var rowIndex = rowIndexes[i];

    myBindingSource.RemoveAt(rowIndex);
}

然后,您将使用数据适配器以相同的方式保存更改。

您没有提到您在 DataGridView 中显示的项目类型。 为了简化讨论,我假设您展示了一系列Products

class Product
{
    ...
}

将您的表单与数据库访问分开

您需要访问您的数据库。 您的表单不必知道数据的存储方式和存储位置。 它所需要知道的是,您可以通过某种方式将数据放入其中,然后再将其取回。

这样做的好处是您可以将表单与数据库分离。 如果您稍后决定更改访问数据库的方式,例如您决定使用实体框架而不是 SQL,那么您的表单不必更改。 或者,如果您需要以不同的形式访问数据库,您可以重用该数据库。

隐藏数据库访问方式的 class 通常称为Repository 您可以在其中存储物品。 稍后您可以查询存储的项目。

在您的存储库中,您至少需要以下方法

Interface IProductRepository
{
     IEnumerable<Product> FetchProducts(...); // TODO: invent a suitable name
     void DeleteProducts(IEnumerable<Product> productsToDelete);

     ... // other useful methods
}

FetchProducts将获取您需要在 DataGridView 中显示的产品。 由于您的存储库不知道产品显示在 DataGridView 中,因此我不能使用FetchProductsToDisplay或类似的东西。 参数必须过滤产品。

class ProductRepository : IProductRepository
{
    // TODO: implement
}

实施不是这个问题的一部分。 您可以使用实体框架、Dapper 或普通的旧 SQL。 class 的用户不会知道,也不必知道您如何访问数据。

访问 DataGridView 中的产品

您说您已将数据数据绑定到 DataGridView。 因此,我假设您知道如何实例化 DataGridView、其列等。详细信息不在此问题范围内。

属性将允许您访问显示的产品:

// access all Products in the DataGridView
public BindingList<Product> DisplayedProducts
{
    get => (BindingList<Product>) this.DataGridView1.DataSource;
    set => this.DataGridView1.DataSource = value;
}

// returns the current Product or null if there is no current Product
Product CurrentProduct => this.DataGridView1.CurrentRow?.DataBoundItem as Product;

// returns the (possible empty) sequence of selected Products
IEnumerable<Product> SelectedProducts => this.DataGridView1.SelectedRows
    .Cast<DataGridViewRow>()
    .Select(row => row.DataBoundItem)
    .Cast<Product>();

换句话说:从 SelectedRows 的序列中,将每一行转换为 DataGridViewRow。 从此 DataGridViewRows 序列中的每一行获取 DataBoundItem 的值。 将每个 DataBoundItem 转换为 Product。

使用初始产品列表填充 DataGridView:

IProductRepository ProductRepository {get;} // initialized in constructor

void InitializeProductsDataGridView()
{
    IEnumerable<Product> productsToDisplay = this.ProductRepository.FetchProductsToDisplay(...);
    this.DisplayedProducts = new BindingList<Product>(productsToDisplay.ToList());
}

回到你的问题

我的主要目标是制作一个按钮,用于从用户选择的数据表中删除 SelectedRows。

现在您已经正确定义了对 DataGridView 中产品的访问权限和对数据库的访问权限,这是一个两行方法:

void DeleteSelectedProducts()
{
    IEnumerable<Product> selectedProducts = this.SelectedProducts;
    this.ProductRepository.DeleteProducts(selectedProducts);
}

概括

不要做一个可以做任何事情的大表格。 分开你的顾虑(如果你不知道这个词,谷歌它)。 在这种情况下:将您的表单与对数据库的访问分开,并将对 DataGridView 中产品的访问分开。

这样做的好处是更容易理解你的类是做什么的。 更改它们更容易,无需更改 class 的用户。 测试这些较小的类更容易,并且更容易重用项目。

我的大多数具有 DataGridView 的 forms 都具有我在上面定义的访问属性。 事实上,我创建了通用扩展方法,因此我可以将它们用于每个 DataGridView。 我只需要为他们编写一次单元测试。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM