简体   繁体   English

使用 EF 更新 PK 时出错

[英]Error when updating PK with EF

I´m trying to do an update in an Order_Details table of Northwind database using EF 4.1 (POCO).我正在尝试使用 EF 4.1 (POCO) 在 Northwind 数据库的 Order_Details 表中进行更新。 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:问题是,当我尝试使用新产品更新 OrderDetail 项目时,出现异常:

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.我做了一些谷歌并找到了[this solution] ,说这样做的一种方法是创建新产品的新实例并关联到 Order_Detail 的产品导航属性。

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!谢谢!

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).正确的设计应该有一个单独的列作为 Order Details 表的主键(自动递增)。

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.这将需要两条具有相同产品和订单 ID 的记录。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM