如何解决使用实体框架C#更新一行
我正在使用C#和实体框架开发Windows窗体应用程序。我将客户购买的所有产品放入DGVNewOrder。对于DGVNewOrder中的evry产品,我想为每个出售的产品更新(按名称)库存数量。这是我尝试的代码:'''
Product pro = new Product();
for (int i = 0; i < DGVNewOrder.RowCount - 1; i++)
{
string Soled_Product_name = DGVNewOrder.Rows[i].Cells[0].Value.ToString();
pro = db.Products.Where(d => d.Name == Soled_Product_name ).FirstOrDefault();
int y = Convert.ToInt32(pro.QteInStock); // QteInStock befor selling
int x = Convert.ToInt32(DGVNewOrder.Rows[i].Cells[2].Value); // the sold quantity
pro.QteInStock = y - x; // The remaining quantity after the sale
db.Entry(pro).State = EntityState.Modified;
db.SaveChanges();
}
这里的问题是数量没有更新,但是所有产品的名称都更改为与DGVNewOrder中存在的第一个产品相同的名称 我也试过了
string Soled_Product_name = DGVNewOrder.Rows[i].Cells[0].Value.ToString();
Product c = (from w in db.Products
where w.Name == Soled_Product_name
select w).First();
int y = Convert.ToInt32(pro.QteInStock);
int x = Convert.ToInt32(DGVNewOrder.Rows[i].Cells[2].Value);
c.QteInStock = y - x;
db.Entry(pro).State = EntityState.Modified;
db.SaveChanges();
但给出相同的结果
解决方法
每当您有一个显示集合元素的控件(例如DataGridView,ListView)时,直接编辑控件中的项目通常不是一个好主意。造成这种情况的原因之一是,您需要主动从控件中获取更改的项目。例如,如果控件的显示发生更改,则列的顺序更改了,或者DataGridView中的行的顺序更改了,您必须主动找出更改的内容。
为此使用DataBinding更容易。将需要显示的项目放在BindingList<T>
中,并将其分配给DataGridView.DataSource
。
DataGridViewColum.DataPropertyName
包含应在列中显示的<T>
属性的名称。只要操作员编辑一个值并接受它,就会通知您BindingList已更改。您无需再阅读DataGridView,您将自动知道在BindingList中已更新了完整的DataGridView。甚至添加或删除的行都在BindingList中
示例:
class OrderLine
{
public int Id {get; set;} // primary key of the OrderLine
public int ProductId {get; set;} // foreign key to the Product in this OrderLine
public string ProductDescription {get; set;}
public decimal ProductPrice {get; set;}
public int NrOfItems {get; set;}
public decimal TotalPrice => this.ProductPrice * this.NrOfItems;
}
您想要一个DataGridView来显示ProductId / ProductDescription / ProductPrice / NrOfItems / TotalPrice。
Operatos可以在DataGridView中添加新的OrderLine,或删除OrderLine。他们无法更改ProductId / ProductDescription / ProductPrice,但可以更改NrOfItems。
DataGridView dgv = new DataGridView();
// Add columns. This is some tedious work,usually it is best to let visual studio designer
// do this
dgv.Columns.Add(new DataGridViewColumn()
{
Name = "columnProductId",DataProperty = nameof(OrderLine.ProductId),ReadOnly = true;
...
}
您所有列的等。
现在用一些初始项填充您的datagridview:
IList<OrderLine> initialOrderLines = ...
var actualOrderLines = new BindingList<OrderLine(initialOrderLines);
dgv.DataSource = actualOrderLines;
如果没有初始订单行,请使用默认构造函数
然后,所有列都填充了实际的OrderLines。在编辑过程中,此集合会自动更新。如果操作员添加了新行,则会自动使用默认的OrderLine对其进行初始化,或者,如果您愿意,如果您订阅事件BindingList.OnAddingNew
,则可以提供OrderLine。
最后,在操作员完成所有更改之后,他按下按钮:
void OnButtonReady_Clicked(object sender,...)
{
// you can be certain the the BindingList is up-to-date
// you don't have to fetch the items from the DataGridView anymore.
this.UpdateStock(this.actualOrderLines);
}
private void UpdateStock(IEnumerable<OrderLine> actualOrderLines)
{
foreach (OrderLine orderLine in actualOrderLines)
{
// TODO: update the stock
}
}
有趣的是:如果更改了“列”顺序或对“行”进行了排序,那么这对您的实际OrderLines无效。如果将来您决定添加或删除列:没问题,您只知道您的信息在ActualOrderLines中,谁在乎如何向操作员显示信息,或他如何编辑信息。
最后一件好事:如果要通过简单的鼠标单击标题来对列进行排序,请考虑Nuget Package BindingListView
使用BindingList<T>
代替BindingListView<T>
var initialOrderLines = ...
BindingListView<OrderLine> actualOrderLines = new BindingListView<OrderLine>(initialOrderLines);
this.dgv.DataSource = actualOrderLines;
宾果游戏:只要单击标题,项目的列属性就按升序或降序排列。甚至字形(显示排序顺序的小箭头)也正确显示。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。