使用EF更新PK时出错

时间:2011-06-11 00:23:32

标签: c# asp.net entity-framework poco ef-code-first

我正在尝试使用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项目时,我得到了例外:

The property 'ProductID' is part of the object's key information and cannot be modified.

代码是:

        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();

我做了一些谷歌并找到[this solution],说这样做的方法是创建新产品的新实例并关联到Order_Detail的产品导航属性。

但是这样做我得到另一个例外:

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.

修改后的代码:

        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();

如何让用户更改详细信息项中的产品?我真的不喜欢删除整个记录并使用新产品重新创建它的想法。它味道很糟糕!

谢谢!

1 个答案:

答案 0 :(得分:1)

该表设计不佳。实际上,您必须删除并重新添加整行。

正确的设计会有一个单独的列作为Order Details表的主键(自动增量)。

除了您发现的限制之外,该表不支持客户购买一个,以半价购买一个的情况。这将需要两个具有相同产品和订单ID的记录。