0

I have an winforms order taking app for a restaurant. On startup I read the list of products available as this:

var products = context.Products.AsNoTracking().OrderBy(p => p.Id).ToList();

When the user clicks the button corresponding to a menu Item, I identify the product to be added to the order like this:

var product = products.FirstOrDefault(p => p.Id == menuItem.ProductId);
var orderItem = new OrderItem
{
    ProductId = product.Id,
    Quantity = 1,
    UnitPrice = product.Price,
    ListValue = 1 * product.Price,
    Product = product
};

Here is the OrderItem entity:

public partial class OrderItem
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
    public int OrderId { get; set; }
    public int ProductId { get; set; }
    public decimal Quantity { get; set; }
    public decimal UnitPrice { get; set; }
    public decimal TotalValue { get; set; }

    public Order Order { get; set; }
    public Product Product { get; set; }
}

After saving the order, some strange things happen (for me anyway): The product in the list changes its Id, as if it is a new product, with the same attributes. Also after context.SaveChanges() in the database I will have 2 rows of the same product.

Anyone can point out what I am doing wrong?

H Mihail
  • 613
  • 8
  • 18
  • Can you include definition of OrderItem entity? The problem is probably in that Product = product line... especially since you are getting those products with AsNoTracking(). – nikib3ro Feb 19 '15 at 06:55
  • 1
    See http://stackoverflow.com/questions/12211680/what-difference-does-asnotracking-make – Jehof Feb 19 '15 at 06:55
  • The behaviour is the same if I remove `AsNoTracking()` – H Mihail Feb 19 '15 at 07:03

3 Answers3

1

When you Add the Order, the Product is also changed to Added. You can simply prevent this by removing the assignment

Product = product

It is enough to set ProductId.

Gert Arnold
  • 105,341
  • 31
  • 202
  • 291
  • Yes, I thought about that. But I need the `Product.Name` to display in the UI. I solved it by reattaching the `products` to the new context when saving. – H Mihail Feb 19 '15 at 07:17
1

You have obtained the list of products as NoTracking. But then you assign it to the product in the orderitem, effectively pulling the object back in. If you just leave out that statement and do this instead

var product = products.FirstOrDefault(p => p.Id == menuItem.ProductId);
var orderItem = new OrderItem
{
    ProductId = product.Id,
    Quantity = 1,
    UnitPrice = product.Price,
    ListValue = 1 * product.Price,
    //Product = product don't do this
};

then it will work ok.

Philip Stuyck
  • 7,344
  • 3
  • 28
  • 39
  • I was using `product` in `orderItem` to display its name. Should I use a different way to display the product name in orderItem? – H Mihail Feb 20 '15 at 15:52
  • You can solve that by creating a simple translation function that translates the id to the name by using your products variable.The thing is that the product is really defined by the id. And you should not have to pull in the product if your original idea was to use notracking. – Philip Stuyck Feb 20 '15 at 16:11
  • Thanks. I will give it a try. My idea to not use tracking for the products was to avoid frequent database calls, since the products list does not change while application is running. – H Mihail Feb 20 '15 at 16:14
  • using notracking saves memory because there is no change tracking on those objects. A perfect fit for what you want. Please at least upvote peoples answers that tried to help you. ;-) You can also mark your own answer as answer so it is clear that the problem is solved. – Philip Stuyck Feb 20 '15 at 16:18
  • It worked, finally! After one whole day. Thanks @Philip! – H Mihail Feb 20 '15 at 16:49
0

After reading the question @Jehof mentioned, I solved it by reattaching the products to the new context in which SaveChanges() occurs:

products.ForEach(p => context.Products.Attach(p));
context.SaveChanges();

Thanks for your comments!

H Mihail
  • 613
  • 8
  • 18