C# 实体框架6.1:子对象上的CRUD
我使用来自存储库的对象列表填充数据网格,如下所示:C# 实体框架6.1:子对象上的CRUD,c#,wpf,entity-framework,binding,C#,Wpf,Entity Framework,Binding,我使用来自存储库的对象列表填充数据网格,如下所示: public static IEnumerable<Order> GetOrdersForDataGrid() { IEnumerable<Order> query; using (RSDContext = new RSDContext()) { query = context.Orders.Include(o=>o.OrderD
public static IEnumerable<Order> GetOrdersForDataGrid()
{
IEnumerable<Order> query;
using (RSDContext = new RSDContext())
{
query = context.Orders.Include(o=>o.OrderDetails).ToList();
}
return query;
}
OrderEditWindow orderEdit = new OrderEditWindow();
orderEdit.SelectedOrder = SelectedOrder;
orderEdit.ShowDialog();
private void AddProductDetailButton_OnClick(object sender, RoutedEventArgs e)
{
if (!ValidateProductDetail())
return;
var _selectedProduct = ProductAutoCompleteBox.SelectedItem as Product;
var selectedProduct = ProductsRepository.GetProductById(_selectedProduct.ProductId);
OrderDetail orderDetail = new OrderDetail();
orderDetail.Price = selectedProduct.Price;
orderDetail.ProductCode = selectedProduct.Code;
orderDetail.ProductName = selectedProduct.Name;
orderDetail.Quantity = int.Parse(QuantityNumericUpDown.Value.ToString());
orderDetail.Um = selectedProduct.Um;
orderDetail.Total = selectedProduct.Price * int.Parse(QuantityNumericUpDown.Value.ToString());
orderDetail.Group = selectedProduct.Subgroup.Group.Name;
orderDetail.Subgroup = selectedProduct.Subgroup.Name;
orderDetail.SupplierName = selectedProduct.Supplier.Name;
//orderDetail.Order=SelectedOrder;
//orderDetail.OrderId = SelectedOrder.OrderId;
SelectedOrder.OrderDetails.Add(orderDetail);
ProductAutoCompleteBox.Text = string.Empty;
QuantityNumericUpDown.Value = 1;
ProductAutoCompleteBox.Focus();
}
public class Order : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public Order()
{
_OrderDetails = new ObservableCollection<OrderDetail>();
_OrderDetails.CollectionChanged += _OrderDetails_CollectionChanged;
}
void _OrderDetails_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (e.NewItems != null)
AttachProductChangedEventHandler(e.NewItems.Cast<OrderDetail>());
if (e.OldItems != null)
CalcualteTotals();
}
[NotMapped]
public decimal CalculatedTotal
{
get
{
return OrderDetails.Sum(x => x.Total);
}
}
public int OrderId { get; set; }
private int _Number;
public int Number
{
get { return _Number; }
set
{
_Number = value;
NotifyPropertyChanged("Number");
}
}
private DateTime _Date;
public DateTime Date
{
get { return _Date; }
set
{
_Date = value;
NotifyPropertyChanged("Date");
}
}
private bool _Canceled;
public bool Canceled
{
get { return _Canceled; }
set
{
_Canceled = value;
NotifyPropertyChanged("Canceled");
}
}
private string _ClientName;
public string ClientName
{
get { return _ClientName; }
set
{
_ClientName = value;
NotifyPropertyChanged("ClientName");
}
}
private string _ClientPhone;
public string ClientPhone
{
get { return _ClientPhone; }
set
{
_ClientPhone = value;
NotifyPropertyChanged("ClientPhone");
}
}
private string _DeliveryAddress;
public string DeliveryAddress
{
get { return _DeliveryAddress; }
set
{
_DeliveryAddress = value;
NotifyPropertyChanged("DeliveryAddress");
}
}
private decimal _Transport;
public decimal Transport
{
get { return _Transport; }
set
{
_Transport = value;
NotifyPropertyChanged("Transport");
}
}
private decimal _Total;
public decimal Total
{
get { return _Total; }
set
{
_Total = value;
NotifyPropertyChanged("Total");
}
}
private ObservableCollection<OrderDetail> _OrderDetails;
public virtual ObservableCollection<OrderDetail> OrderDetails
{
//get { return _OrderDetails ?? (_OrderDetails = new ObservableCollection<OrderDetail>()); }
get
{
return _OrderDetails;
}
set
{
_OrderDetails = value;
NotifyPropertyChanged("OrderDetails");
}
}
private void AttachProductChangedEventHandler(IEnumerable<OrderDetail> orderDetails)
{
foreach (var p in orderDetails)
{
p.PropertyChanged += (sender, e) =>
{
switch (e.PropertyName)
{
case "Quantity":
case "Price":
case "Total":
CalcualteTotals();
break;
}
};
}
CalcualteTotals();
}
public void CalcualteTotals()
{
NotifyPropertyChanged("CalculatedTotal");
}
public void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this,
new PropertyChangedEventArgs(propertyName));
}
}
}
在这里,我将窗口的DataContext设置为:
DataContext = SelectedOrder;
在这个窗口中,我有另一个数据网格,它绑定到Order
的OrderDetails
集合属性。问题在于OrderDetails
上的CRUD操作。例如,在添加新的orderDetail后,如下所示:
public static IEnumerable<Order> GetOrdersForDataGrid()
{
IEnumerable<Order> query;
using (RSDContext = new RSDContext())
{
query = context.Orders.Include(o=>o.OrderDetails).ToList();
}
return query;
}
OrderEditWindow orderEdit = new OrderEditWindow();
orderEdit.SelectedOrder = SelectedOrder;
orderEdit.ShowDialog();
private void AddProductDetailButton_OnClick(object sender, RoutedEventArgs e)
{
if (!ValidateProductDetail())
return;
var _selectedProduct = ProductAutoCompleteBox.SelectedItem as Product;
var selectedProduct = ProductsRepository.GetProductById(_selectedProduct.ProductId);
OrderDetail orderDetail = new OrderDetail();
orderDetail.Price = selectedProduct.Price;
orderDetail.ProductCode = selectedProduct.Code;
orderDetail.ProductName = selectedProduct.Name;
orderDetail.Quantity = int.Parse(QuantityNumericUpDown.Value.ToString());
orderDetail.Um = selectedProduct.Um;
orderDetail.Total = selectedProduct.Price * int.Parse(QuantityNumericUpDown.Value.ToString());
orderDetail.Group = selectedProduct.Subgroup.Group.Name;
orderDetail.Subgroup = selectedProduct.Subgroup.Name;
orderDetail.SupplierName = selectedProduct.Supplier.Name;
//orderDetail.Order=SelectedOrder;
//orderDetail.OrderId = SelectedOrder.OrderId;
SelectedOrder.OrderDetails.Add(orderDetail);
ProductAutoCompleteBox.Text = string.Empty;
QuantityNumericUpDown.Value = 1;
ProductAutoCompleteBox.Focus();
}
public class Order : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public Order()
{
_OrderDetails = new ObservableCollection<OrderDetail>();
_OrderDetails.CollectionChanged += _OrderDetails_CollectionChanged;
}
void _OrderDetails_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (e.NewItems != null)
AttachProductChangedEventHandler(e.NewItems.Cast<OrderDetail>());
if (e.OldItems != null)
CalcualteTotals();
}
[NotMapped]
public decimal CalculatedTotal
{
get
{
return OrderDetails.Sum(x => x.Total);
}
}
public int OrderId { get; set; }
private int _Number;
public int Number
{
get { return _Number; }
set
{
_Number = value;
NotifyPropertyChanged("Number");
}
}
private DateTime _Date;
public DateTime Date
{
get { return _Date; }
set
{
_Date = value;
NotifyPropertyChanged("Date");
}
}
private bool _Canceled;
public bool Canceled
{
get { return _Canceled; }
set
{
_Canceled = value;
NotifyPropertyChanged("Canceled");
}
}
private string _ClientName;
public string ClientName
{
get { return _ClientName; }
set
{
_ClientName = value;
NotifyPropertyChanged("ClientName");
}
}
private string _ClientPhone;
public string ClientPhone
{
get { return _ClientPhone; }
set
{
_ClientPhone = value;
NotifyPropertyChanged("ClientPhone");
}
}
private string _DeliveryAddress;
public string DeliveryAddress
{
get { return _DeliveryAddress; }
set
{
_DeliveryAddress = value;
NotifyPropertyChanged("DeliveryAddress");
}
}
private decimal _Transport;
public decimal Transport
{
get { return _Transport; }
set
{
_Transport = value;
NotifyPropertyChanged("Transport");
}
}
private decimal _Total;
public decimal Total
{
get { return _Total; }
set
{
_Total = value;
NotifyPropertyChanged("Total");
}
}
private ObservableCollection<OrderDetail> _OrderDetails;
public virtual ObservableCollection<OrderDetail> OrderDetails
{
//get { return _OrderDetails ?? (_OrderDetails = new ObservableCollection<OrderDetail>()); }
get
{
return _OrderDetails;
}
set
{
_OrderDetails = value;
NotifyPropertyChanged("OrderDetails");
}
}
private void AttachProductChangedEventHandler(IEnumerable<OrderDetail> orderDetails)
{
foreach (var p in orderDetails)
{
p.PropertyChanged += (sender, e) =>
{
switch (e.PropertyName)
{
case "Quantity":
case "Price":
case "Total":
CalcualteTotals();
break;
}
};
}
CalcualteTotals();
}
public void CalcualteTotals()
{
NotifyPropertyChanged("CalculatedTotal");
}
public void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this,
new PropertyChangedEventArgs(propertyName));
}
}
}
然后我从存储库调用update方法:
public static void UpdateOrder(Order order)
{
using (RSDContext context = new RSDContext())
{
context.Orders.Attach(order);
context.Entry(order).State = EntityState.Modified;
context.SaveChanges();
}
}
我得到一个关于OrderId的错误。如果我手动设置导航属性和id,我不会得到错误,但更改不会保存到数据库中
我的订单
型号如下:
public static IEnumerable<Order> GetOrdersForDataGrid()
{
IEnumerable<Order> query;
using (RSDContext = new RSDContext())
{
query = context.Orders.Include(o=>o.OrderDetails).ToList();
}
return query;
}
OrderEditWindow orderEdit = new OrderEditWindow();
orderEdit.SelectedOrder = SelectedOrder;
orderEdit.ShowDialog();
private void AddProductDetailButton_OnClick(object sender, RoutedEventArgs e)
{
if (!ValidateProductDetail())
return;
var _selectedProduct = ProductAutoCompleteBox.SelectedItem as Product;
var selectedProduct = ProductsRepository.GetProductById(_selectedProduct.ProductId);
OrderDetail orderDetail = new OrderDetail();
orderDetail.Price = selectedProduct.Price;
orderDetail.ProductCode = selectedProduct.Code;
orderDetail.ProductName = selectedProduct.Name;
orderDetail.Quantity = int.Parse(QuantityNumericUpDown.Value.ToString());
orderDetail.Um = selectedProduct.Um;
orderDetail.Total = selectedProduct.Price * int.Parse(QuantityNumericUpDown.Value.ToString());
orderDetail.Group = selectedProduct.Subgroup.Group.Name;
orderDetail.Subgroup = selectedProduct.Subgroup.Name;
orderDetail.SupplierName = selectedProduct.Supplier.Name;
//orderDetail.Order=SelectedOrder;
//orderDetail.OrderId = SelectedOrder.OrderId;
SelectedOrder.OrderDetails.Add(orderDetail);
ProductAutoCompleteBox.Text = string.Empty;
QuantityNumericUpDown.Value = 1;
ProductAutoCompleteBox.Focus();
}
public class Order : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public Order()
{
_OrderDetails = new ObservableCollection<OrderDetail>();
_OrderDetails.CollectionChanged += _OrderDetails_CollectionChanged;
}
void _OrderDetails_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (e.NewItems != null)
AttachProductChangedEventHandler(e.NewItems.Cast<OrderDetail>());
if (e.OldItems != null)
CalcualteTotals();
}
[NotMapped]
public decimal CalculatedTotal
{
get
{
return OrderDetails.Sum(x => x.Total);
}
}
public int OrderId { get; set; }
private int _Number;
public int Number
{
get { return _Number; }
set
{
_Number = value;
NotifyPropertyChanged("Number");
}
}
private DateTime _Date;
public DateTime Date
{
get { return _Date; }
set
{
_Date = value;
NotifyPropertyChanged("Date");
}
}
private bool _Canceled;
public bool Canceled
{
get { return _Canceled; }
set
{
_Canceled = value;
NotifyPropertyChanged("Canceled");
}
}
private string _ClientName;
public string ClientName
{
get { return _ClientName; }
set
{
_ClientName = value;
NotifyPropertyChanged("ClientName");
}
}
private string _ClientPhone;
public string ClientPhone
{
get { return _ClientPhone; }
set
{
_ClientPhone = value;
NotifyPropertyChanged("ClientPhone");
}
}
private string _DeliveryAddress;
public string DeliveryAddress
{
get { return _DeliveryAddress; }
set
{
_DeliveryAddress = value;
NotifyPropertyChanged("DeliveryAddress");
}
}
private decimal _Transport;
public decimal Transport
{
get { return _Transport; }
set
{
_Transport = value;
NotifyPropertyChanged("Transport");
}
}
private decimal _Total;
public decimal Total
{
get { return _Total; }
set
{
_Total = value;
NotifyPropertyChanged("Total");
}
}
private ObservableCollection<OrderDetail> _OrderDetails;
public virtual ObservableCollection<OrderDetail> OrderDetails
{
//get { return _OrderDetails ?? (_OrderDetails = new ObservableCollection<OrderDetail>()); }
get
{
return _OrderDetails;
}
set
{
_OrderDetails = value;
NotifyPropertyChanged("OrderDetails");
}
}
private void AttachProductChangedEventHandler(IEnumerable<OrderDetail> orderDetails)
{
foreach (var p in orderDetails)
{
p.PropertyChanged += (sender, e) =>
{
switch (e.PropertyName)
{
case "Quantity":
case "Price":
case "Total":
CalcualteTotals();
break;
}
};
}
CalcualteTotals();
}
public void CalcualteTotals()
{
NotifyPropertyChanged("CalculatedTotal");
}
public void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this,
new PropertyChangedEventArgs(propertyName));
}
}
}
我真的在尝试使用某种工作单元,但我不明白我应该如何在具有子集合的对象上应用CRUD,同时保持UI的更新(通过在ObservableCollection
中工作并使用绑定ClientPhone,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged
我的父窗口在我键入时更新)
最终工作解决方案:
using (RSDContext context = new RSDContext())
{
var details = order.OrderDetails;
order.OrderDetails = null;
List<int> OriginalOrderDetailsIds =
context.OrderDetails.Where(o => o.OrderId == order.OrderId).Select(o => o.OrderDetailId).ToList();
List<int> CurrentOrderDetailsIds = details.Select(o => o.OrderDetailId).ToList();
List<int> DeletedOrderDetailsIds = OriginalOrderDetailsIds.Except(CurrentOrderDetailsIds).ToList();
context.Entry(order).State = EntityState.Modified;
foreach (var deletedOrderDetailId in DeletedOrderDetailsIds)
{
context.Entry(context.OrderDetails.Single(o => o.OrderDetailId == deletedOrderDetailId)).State = EntityState.Deleted;
}
foreach (OrderDetail detail in details)
{
// Add.
if (detail.OrderDetailId == 0)
{
detail.OrderId = order.OrderId;
context.Entry(detail).State = EntityState.Added;
}
// Update.
else
{
context.Entry(detail).State = EntityState.Modified;
}
}
context.SaveChanges();
}
使用(RSDContext context=new RSDContext())
{
var details=order.OrderDetails;
order.OrderDetails=null;
列出原始或详细信息=
其中(o=>o.OrderId==order.OrderId).Select(o=>o.OrderDetailId.ToList();
List CurrentOrderDetailsIds=details.Select(o=>o.OrderDetailId.ToList();
List DeletedOrderDetailsIds=originalordertailsids.Except(CurrentOrderDetailsIds.ToList();
context.Entry(order).State=EntityState.Modified;
foreach(DeletedOrderDetailsIds中的变量deletedOrderDetailId)
{
context.Entry(context.OrderDetails.Single(o=>o.OrderDetailId==deletedOrderDetailId)).State=EntityState.Deleted;
}
foreach(详细的订单详细信息)
{
//加上。
if(detail.OrderDetailId==0)
{
detail.OrderId=order.OrderId;
context.Entry(detail.State=EntityState.Added;
}
//更新。
其他的
{
context.Entry(detail.State=EntityState.Modified;
}
}
SaveChanges();
}
您可以通过这种方式添加和更新子项,但不能确定ui中已删除的订单详细信息。如果您不想从实体获取订单,则需要在OrderDetail中为已删除的OrderDetail做某种标记
using (RSDContext context = new RSDContext())
{
var details = order.OrderDetails;
order.OrderDetails = null;
context.Entry(order).State = EntityState.Modified;
foreach (var detail in details)
{
if (detail.Id == 0)
{
// Adds.
detail.OrderId = order.Id;
context.Entry(detail).State = EntityState.Added;
}
else if (detail.IsDeleted)
// Adds new property called 'IsDeleted'
// and add [NotMapped] attribute
// then mark this property as true from the UI for deleted items.
{
// Deletes.
context.Entry(detail).State = EntityState.Deleted;
}
else
{
// Updates.
context.Entry(detail).State = EntityState.Modified;
}
}
order.OrderDetails = details;
context.SaveChanges();
}
我认为问题不在wpf中,但在EF中,您需要从包含详细信息的上下文中获取订单,然后将订单ui与订单数据库合并。如果我这样做,它会工作,但我会松开实时更新的ui。我知道我可以实现发布/订阅模式(我必须先学习)但是我希望有一个解决方案,因为我觉得拿一个对象,修改它的所有方面,然后把它推回db是很自然的。我认为
把它推回db
,因为子集合不仅仅是通过改变父对象的状态来完成的,你需要从ui和dbI合并子集合,我将研究如何做到这一点那。谢谢。*可能会循环遍历所有子对象并手动插入/删除它们。我会在保存方法中尝试。我想如果我在集合更改事件中这样做,我会打破我的工作单位心态。是的,这很有效。谢谢。我想这是最好的方法。我会研究如何知道我认为我需要的实体被删除要管理我自己,请删除删除代码,因为现在我使用Delete命令,当我处于此循环中时,我看不到已删除的对象。谢谢。*我想我可以与db中的对象进行比较并删除它们。@andySF,您可以添加名为IsDeleted
的新属性并添加[NotMapped]
属性,然后在删除项目时从UI中将其标记为true(通过订阅集合更改事件或删除按钮单击事件?)我在集合更改事件上设置了IsDeleted=true,但后来我意识到这是无用的,因为在foreach循环中,我无法迭代删除的项目,因为它们不在那里。在这种情况下,这是有意义的,我认为UI中的更改将通过某种保存b应用然后将删除的项目存储在其他集合中(+将其标记为已删除),并在发送到后端之前重新添加到集合中