开发者

Error when updating PK with EF

开发者 https://www.devze.com 2023-03-12 08:01 出处:网络
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:

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 Pro开发者_如何学编程ductID { 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!


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.

0

精彩评论

暂无评论...
验证码 换一张
取 消