使用 EF 更新 PK 时出错
我正在尝试使用 EF 4.1 (POCO) 在 Northwind 数据库的 Order_Details 表中进行更新。 该表定义为:
[MetadataType(typeof(Order_DetailMetadata))]
public partial class Order_Detail
{
public int OrderID { get; set; }
public int ProductID { get; set; }
public decimal UnitPrice { get; set; }
public short Quantity { get; set; }
public float Discount { get; set; }
public virtual Order Order { get; set; }
public virtual Product Product { get; set; }
}
public class Order_DetailMetadata
{
[Key]
[Required]
[DisplayNameLocalized("Model_OrderDetail_OrderID_DisplayName")]
public int OrderID { get; set; }
[Key]
[Required]
[DisplayNameLocalized("Model_OrderDetail_ProductID_DisplayName")]
public int ProductID { get; set; }
[Required]
[Range(0.00, 9999.99, ErrorMessageResourceType = typeof(Messages), ErrorMessageResourceName = "Model_Range_Float_Error")]
[DisplayNameLocalized("Model_OrderDetail_UnitPrice_DisplayName")]
public decimal UnitPrice { get; set; }
[Required]
[Range(1, short.MaxValue, ErrorMessageResourceType = typeof(Messages), ErrorMessageResourceName = "Model_Range_Integer_Error")]
[DisplayNameLocalized("Model_OrderDetail_Quantity_DisplayName")]
public short Quantity { get; set; }
[Required]
[DisplayNameLocalized("Model_OrderDetail_Discount_DisplayName")]
[Range(0.00, 1.00, ErrorMessageResourceType = typeof(Messages), ErrorMessageResourceName = "Model_Range_Float_Error")]
public float Discount { get; set; }
}
问题是,当我尝试使用新产品更新 OrderDetail 项时,出现异常:
属性“ProductID”是对象关键信息的一部分,无法修改。
属性“ProductID”是对象关键信息的一部分,无法修改。代码>
代码是:
int orderId = (int)detailsList.DataKeys[e.ItemIndex]["OrderID"];
int productId = (int)detailsList.DataKeys[e.ItemIndex]["ProductID"];
Order_Detail detail = repository.GetOrderDetail(orderId, productId);
detail.ProductID = int.Parse(e.NewValues["ProductID"] as string, CultureInfo.CurrentCulture);
detail.UnitPrice = decimal.Parse(e.NewValues["UnitPrice"] as string, CultureInfo.CurrentCulture);
detail.Quantity = short.Parse(e.NewValues["Quantity"] as string, CultureInfo.CurrentCulture);
detail.Discount = float.Parse(e.NewValues["Discount"] as string, CultureInfo.CurrentCulture);
repository.UpdateOrderDetail(detail);
repository.Save();
我做了一些谷歌并发现[此解决方案],表示执行此操作的一种方法是创建新产品的新实例并关联到 Order_Detail 的产品导航属性。
但这样做时我得到另一个异常:
发生引用完整性约束违规:当依赖对象未更改时,作为引用完整性约束一部分的主键属性无法更改,除非将其设置为关联的主体对象。必须跟踪主体对象,并且不能将其标记为删除。
修改后的代码:
int orderId = (int)detailsList.DataKeys[e.ItemIndex]["OrderID"];
int productId = (int)detailsList.DataKeys[e.ItemIndex]["ProductID"];
int newProductId = int.Parse(e.NewValues["ProductID"] as string, CultureInfo.CurrentCulture);
Order_Detail detail = repository.GetOrderDetail(orderId, productId);
detail.UnitPrice = decimal.Parse(e.NewValues["UnitPrice"] as string, CultureInfo.CurrentCulture);
detail.Quantity = short.Parse(e.NewValues["Quantity"] as string, CultureInfo.CurrentCulture);
detail.Discount = float.Parse(e.NewValues["Discount"] as string, CultureInfo.CurrentCulture);
Product newProduct = null;
// the product has been changed (it is part of the PK and cannot be directly changed)
if (productId != newProductId)
{
// get an instance of the new product
newProduct = repository.GetProduct(newProductId);
// update the detail item with the new product instance
detail.Product = newProduct;
}
repository.UpdateOrderDetail(detail);
repository.Save();
我可以做什么来允许用户更改详细信息项中的产品?我真的不喜欢删除整个记录并使用新产品重新创建它的想法。味道很难闻!
谢谢!
I´m trying to do an update in an Order_Details table of Northwind database using EF 4.1 (POCO).
The table is defined as:
[MetadataType(typeof(Order_DetailMetadata))]
public partial class Order_Detail
{
public int OrderID { get; set; }
public int ProductID { get; set; }
public decimal UnitPrice { get; set; }
public short Quantity { get; set; }
public float Discount { get; set; }
public virtual Order Order { get; set; }
public virtual Product Product { get; set; }
}
public class Order_DetailMetadata
{
[Key]
[Required]
[DisplayNameLocalized("Model_OrderDetail_OrderID_DisplayName")]
public int OrderID { get; set; }
[Key]
[Required]
[DisplayNameLocalized("Model_OrderDetail_ProductID_DisplayName")]
public int ProductID { get; set; }
[Required]
[Range(0.00, 9999.99, ErrorMessageResourceType = typeof(Messages), ErrorMessageResourceName = "Model_Range_Float_Error")]
[DisplayNameLocalized("Model_OrderDetail_UnitPrice_DisplayName")]
public decimal UnitPrice { get; set; }
[Required]
[Range(1, short.MaxValue, ErrorMessageResourceType = typeof(Messages), ErrorMessageResourceName = "Model_Range_Integer_Error")]
[DisplayNameLocalized("Model_OrderDetail_Quantity_DisplayName")]
public short Quantity { get; set; }
[Required]
[DisplayNameLocalized("Model_OrderDetail_Discount_DisplayName")]
[Range(0.00, 1.00, ErrorMessageResourceType = typeof(Messages), ErrorMessageResourceName = "Model_Range_Float_Error")]
public float Discount { get; set; }
}
The problem is that when I try to update an OrderDetail item with a new Product, I get the exception:
The property 'ProductID' is part of the object's key information and cannot be modified.
The code is:
int orderId = (int)detailsList.DataKeys[e.ItemIndex]["OrderID"];
int productId = (int)detailsList.DataKeys[e.ItemIndex]["ProductID"];
Order_Detail detail = repository.GetOrderDetail(orderId, productId);
detail.ProductID = int.Parse(e.NewValues["ProductID"] as string, CultureInfo.CurrentCulture);
detail.UnitPrice = decimal.Parse(e.NewValues["UnitPrice"] as string, CultureInfo.CurrentCulture);
detail.Quantity = short.Parse(e.NewValues["Quantity"] as string, CultureInfo.CurrentCulture);
detail.Discount = float.Parse(e.NewValues["Discount"] as string, CultureInfo.CurrentCulture);
repository.UpdateOrderDetail(detail);
repository.Save();
I did some google and found [this solution], saying that a way to do this is creating a new instance of the new Product and associating to the Order_Detail´s Product navigation property.
But doing this I get another exception:
A referential integrity constraint violation occurred: A primary key property that is a part of referential integrity constraint cannot be changed when the dependent object is Unchanged unless it is being set to the association's principal object. The principal object must be tracked and not marked for deletion.
The modified code:
int orderId = (int)detailsList.DataKeys[e.ItemIndex]["OrderID"];
int productId = (int)detailsList.DataKeys[e.ItemIndex]["ProductID"];
int newProductId = int.Parse(e.NewValues["ProductID"] as string, CultureInfo.CurrentCulture);
Order_Detail detail = repository.GetOrderDetail(orderId, productId);
detail.UnitPrice = decimal.Parse(e.NewValues["UnitPrice"] as string, CultureInfo.CurrentCulture);
detail.Quantity = short.Parse(e.NewValues["Quantity"] as string, CultureInfo.CurrentCulture);
detail.Discount = float.Parse(e.NewValues["Discount"] as string, CultureInfo.CurrentCulture);
Product newProduct = null;
// the product has been changed (it is part of the PK and cannot be directly changed)
if (productId != newProductId)
{
// get an instance of the new product
newProduct = repository.GetProduct(newProductId);
// update the detail item with the new product instance
detail.Product = newProduct;
}
repository.UpdateOrderDetail(detail);
repository.Save();
What could I do to allow the user to change the Product in a Detail item? I really don´t like the idea of delete the entire record and recreate it with the new Product. It smells very bad!
Thanks!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
桌子设计得很差。事实上,您必须删除并重新添加整行。
正确的设计应该有一个单独的列作为“订单详细信息”表的主键(自动增量)。
除了您发现的限制之外,该表不支持客户以半价购买一件的情况。这需要两条具有相同产品和订单 ID 的记录。
The table is poorly designed. As it is, you will have to delete and re-add the entire row.
A correct design would have a separate column as the primary key for the Order Details table (auto-increment).
In addition to the limitation you found, the table does not support scenarios where the customer would buy one, get one at half price. This would require two records with the same product and order ids.