Ryan Duffing
Ryan Duffing

Reputation: 674

Why does my DBContext.SaveChanges() method change values of the object I'm adding?

I am adding an object to a DBContext collection. Before saving it to the collection, the variables within that object are all correct, after saving it, and looking inside of the DBContext collection using the debugging tools VS2012 has, I notice that all the values inside of the object change. Here is the relevant code:

public class AdmissionsStoreEntities : DbContext
{
    public DbSet<Cart> Carts { get; set; }
    public DbSet<Order> Orders { get; set; }
    public DbSet<OrderDetail> OrderDetails { get; set; }
}

public void AddToCart(Product product)
{
    // Get the matching cart and product instances
    var cartItem = storeDB.Carts.SingleOrDefault(
        c => c.CartId == ShoppingCartId
        && c.ProductId == product.ProductId);

    if (cartItem == null)
    {
        // Create a new cart item if no cart item exists
        cartItem = new Cart
        {
            ProductId = product.ProductId,
            Product = product,
            CartId = ShoppingCartId,
            Count = 1,
            DateCreated = DateTime.Now
        };

        // storeDB is my AdmissionsStoreEntities() object.
        storeDB.Carts.Add(cartItem);
    }
    else
    {
        // If the item does exist in the cart, then add one to the quantity.
        cartItem.Count++;
    }

    // Save Changes (where the changes occur)
    storeDB.SaveChanges();
}

So for example, before saving the cartItem object to storeDB.Carts, the values are as follows:

After saving the changes, the values change for the cartItem, (I also noticed the values are changed for the original object passed into the method). Here are the values afterwards

Why is this happening? If needed I can supply more code.

As requested, this is how I am getting my ShoppingCartId.

public ActionResult AddToCart(int id)
    {
        // Retrieve the product from our ViewData object that holds all current  data        in the SharePoint list
        var addedProduct = ((List<Product>)ViewData["AllProducts"]).Find(x => x.ProductId == id);

        // Get our cart instance.
        var cart = ShoppingCart.GetCart(this.HttpContext);

        // Add product to cart.
        cart.AddToCart(addedProduct);

        // Go back to the main store page for more shopping
        return RedirectToAction("Index");
    }

public static ShoppingCart GetCart(HttpContextBase context)
    {
        var cart = new ShoppingCart();
        cart.ShoppingCartId = cart.GetCartId(context);
        return cart;
    }

public string GetCartId(HttpContextBase context)
    {
        if (context.Session[CartSessionKey] == null)
        {
            if (!string.IsNullOrWhiteSpace(context.User.Identity.Name))
            {
                context.Session[CartSessionKey] = context.User.Identity.Name;
            }
            else
            {
                Guid tempCartId = Guid.NewGuid();

                context.Session[CartSessionKey] = tempCartId.ToString();
            }
        }
        return context.Session[CartSessionKey].ToString();
    }

Links to my Cart and ShoppingCart models are at the following links, as requested by Rob:

Results of debug code Rob provided:

Upvotes: 1

Views: 1070

Answers (2)

Rob
Rob

Reputation: 5588

EDIT

Try removing Product = product:

if (cartItem == null)
    {
        // Create a new cart item if no cart item exists
        cartItem = new Cart
        {
            ProductId = product.ProductId,
            //Product = product,
            CartId = ShoppingCartId,
            Count = 1,
            DateCreated = DateTime.Now
        };

        // storeDB is my AdmissionsStoreEntities() object.
        storeDB.Carts.Add(cartItem);
    }

Settting the ProductId should do the trick, you don't need the actual object.

Upvotes: 1

Ann L.
Ann L.

Reputation: 13965

I am not sure, but I think this may be a side effect of using a static factory method in what is effectively a multi-threaded environment (ASP.NET).

Here's what you've got:

public static ShoppingCart GetCart(HttpContextBase context)
{
    var cart = new ShoppingCart();
    cart.ShoppingCartId = cart.GetCartId(context);
    return cart;
}

You get different values for cart.GetCartId(context) depending on which context you pass, but because this is a static method you only have one copy of the method and its internal variables. If two people call it at the same time, you can have the value of cart.GetCartId() assigned to a different shopping cart than intended.

In your situation I would create a new constructor for ShoppingCart and use it instead of your static factory method:

public ShoppingCart(HttpContextBase context)
{
    ShoppingCartId = GetCartId(context);
}

Upvotes: 0

Related Questions