如何在 DataGridView 中的现有项目中添加数量?

How to add quantity in existing item in DataGridView?

我有一个表单要求用户输入 3 条信息。这些输入是 ProductName、Quantity 和 Price。这 3 个输入将进入数据库,并以单独的形式显示在数据网格视图中。我希望如果我要添加一个项目,它只会与数据库中的项目合并,如果它们具有相同的 input/data。例如,如果我将在我的数据库中添加价格为 50 和数量为 3 的产品“plates”,而我的数据库中已经有具有相同价格的产品“plates”,它将只是合并或者数量将是添加而不是添加新单元格。

这是 Add 按钮的代码:

 double presyo, qty;
 presyo = double.Parse(txtPrice.Text);
 qty = double.Parse(txtQuantity.Text);

con = new SqlConnection(@"Data Source=.\sqlexpress;Initial Catalog=CasaFranca;Integrated Security=True");
con.Open();
cmd = new SqlCommand("INSERT INTO Sales (ProductName, Quantity, Price, Total) VALUES (@ProductName, @Quantity, @Price, @Total)", con);
cmd.Parameters.Add("@ProductName", cmbProduct.Text);
cmd.Parameters.Add("@Quantity", txtQuantity.Text);
cmd.Parameters.Add("@Price", txtPrice.Text);
cmd.Parameters.Add("@Total", (presyo * qty));
cmd.ExecuteNonQuery();
MessageBox.Show("Item sucessfully added to database");

这是一个示例输出:

如您所见,即使它们具有相同的产品名称和价格,它们也是分开存储的。我希望将它们合并为一个并添加它们的数量。我该怎么办?

嗯..你已经以 lowest-level/hardest/most 乏味的方式进行了基本的数据库访问,所以我假设你会想以这种方式继续,但我认为这会让如果您考虑切换到一些旨在进行数据访问(数据集、EF)的库,生活会更轻松,但至少您应该调查 Dapper..

运行 一个更新,如果它产生 0 行,运行 一个插入:

con.Open();
var ins = "INSERT INTO Sales (ProductName, Quantity, Price, Total) VALUES (@ProductName, @Quantity, @Price, @Total)";
var upd = "UPDATE Sales SET Quantity = Quantity + @Quantity, Price = Price + @Price, Total = Total + @Total WHERE ProductName = @ProductName";

cmd = new SqlCommand(upd, con);
cmd.Parameters.Add("@ProductName", cmbProduct.Text);
cmd.Parameters.Add("@Quantity", txtQuantity.Text);
cmd.Parameters.Add("@Price", txtPrice.Text);
cmd.Parameters.Add("@Total", (presyo * qty));
if(cmd.ExecuteNonQuery() == 0){
    cmd.CommandText = ins;
    cmd.ExecuteNonQuery();
}

请注意,这不是很安全;如果两个人在同一时间进行销售,您仍然可以获得重复的行。考虑改为放置主键,在查询中使用它

此外,没有必要存储总数;你可以随时计算它。我还要说的是,除非这是针对保证商品价格相同的单个购物篮,否则如果它是销售历史记录日志,存储多行可能是有意义的,否则您会丢失每次销售价格等信息更改或折扣,如果你所做的只是存储总计

您的问题与DataGridView 无关。由于我看到您显示的 table 已正确更新,因此我认为您已经掌握了显示数据的技巧。

所以让我们专注于您的 SQL。

隐藏访问数据的方式:实施存储库

尝试说服您的项目负责人,如果您可以将界面切换到 Entity Framework 或 Dapper,您的工作效率会更高。

即使你不能说服他,你也需要一个 class 代表你的一行 table,以及一个存储库模式来添加/获取/更新/删除项目table.

像这样:

class Sale
{
    public Id {get; set; }
    public string ProductName {get; set;}
    public int Quantity {get; set;}
    public decimal Price {get; set;}
    public decimal Total {get; set;}
}

存储库 class 是一个 class,它隐藏了您存储销售的方式。它可以在数据库中,但据您所知,它可以在 XML 文件中,或者在 Internet 上的某个地方。或者也许在内部它只是一个用于单元测试的字典。

所以存储库是一个代表一些存储的对象:您可以在其中存储一些 classes 的项目,稍后您可以检索存储的项目,即使在重新启动计算机后也是如此。

隐藏项目存储方式的好处在于,您可以自由更改内部结构,而无需更改使用存储库的代码。 (还有你的单元测试!)。

可能稍后您决定更改数据库,使其具有第一个规范化形式:一个单独的 table 包含产品信息,并且在您的销售中有一个指向产品的外键 table , 因此您可以从产品 table 中获取名称,而不是每次销售都一遍又一遍地使用相同的产品名称。

通过隐藏项目在存储库中的存储方式,存储库的用户将不知道,也不必知道销售实际上存储在单独的 table 中。

典型的存储库class 将实现一个接口。在您的情况下,它将具有如下方法:

interface ISaleRepository
{
    int Add(Sale sale);     // return the primary key
    Sale Fetch(int id);     // fetch by primary key

    Update(Sale sale);
    Remove(int id);

    int Count();           // returns number of Sales;
    IEnumerable<Sale> FetchAll();
}

我不知道你的销售模式,但如果你认为 ProductName 是唯一的,请考虑添加:

Sale Fetch(string productName);  // fetch by unique productName

回到你的问题

您想要“添加或更新”:如果销售已经在数据库中,则只更新数量:

Sale AddOrUpdate(Sale sale);  // returns the updated Sale

如果您对更新后的特卖不感兴趣,请考虑return作废。

您的 AddOrUpdate 可以重用其他 ISaleRepository 方法:

public Sale AddOrUpdate(Sale sale)
{
    // Is there already a Sale?
    Sale existingSale = this.Fetch(sale.ProductName);
    if (existingSale == null)
    {
        // no such Sale yet. Add it now:
        this.Add(sale);  // don't forget to update the Id! Usually done in Add
        existingSale = sale;
    }
    else
    {
        // Sale exists. Update
        existingSale.Quantity += sale.Quantity;
        this.Update(existingSale);
    }
    return existingSale; // return the updated value as it is in the database
}

此解决方案需要两次数据库访问。我假设您不会每秒数百次 AddOrUpdate 项目。在那种情况下,代码的可重用性和简单性会与性能损失进行权衡。

如果真的要看表演,有些SQL方言让你一口气更新

因为我用的是entity framework,所以我的SQL有点生疏,但是this solution gets you on track

const string sqlText = @"
begin tran
    if exists (select * from table with (updlock,serializable) where key = @key)
    begin
       update table set ...
       where key = @key
    end
else
begin
   insert into table (key, ...) values (@key, ...)
end
commit tran";

string dbConnectionString = FetchDbConnectionString();
using (var dbConnection = new dbConnection(dbConnectionString))
{
    using (var dbCommand = dbConnection.CreateCommand())
    {
        dbCommand.CommandText = sqlText;

        // add parameters:
        dbCommand.Parameters.AddWithValue(@ProductName, sale.ProductName);
        dbCommand.Parameters.AddWithValue(@Quantity, sale.Quantity);
        ...

        // Open the database and execute the query:
        dbConnection.Open();
        ...
    }
}

不获取数据的正常添加将是:

dbCommand.ExecuteNonQuery();

如果你return只有添加项目的Id:

return (int)dbCommand.ExecuteScalar();

如果您正在return更新数据:

using (var dbReader = dbcommand.ExecuteReader())
{
     // expect only one item:
     if (dbReader.MoveNext())
     {
         return new Sale
         {
              ProductName = dbReader.GetString(0),
              Quantity = dbReader.GetInt32(1),
              ...
         };
     }
     // else: nothing returned. Decide what to do: exception?
}