无法在实体类型 BusinessEntitys.Product 上设置 field/property CartItems

Unable to set field/property CartItems on entity type BusinessEntitys.Product

我花了很多时间(包括广泛的 Google 搜索)试图找出问题所在。不幸的是,没有成功。 我得到的错误是:"Unable to set field/property CartItems on entity type BusinessEntitys.Product. See InnerException for details." innerExeptionnull。 当我尝试通过 WCF 调用函数 addCartItem 时,addToCart() 函数出现错误。当调用到达 DAL 并尝试将新对象保存在数据库上下文中时,它失败了。

public void AddToCart(int id)
{
    // Retrieve the product from the database.           
    ShoppingCartId = GetCartId();

    CartItem cartItem = new BLFrontend().getAllCartItems().SingleOrDefault(
         c => c.CartItemId == ShoppingCartId
         && c.ProductId == id);
    if (cartItem == null)
    {
        Product temp = new BLFrontend().getAllProducts().SingleOrDefault(
             p => p.ProductId == id);
        // Create a new cart item if no cart item exists.                 
        cartItem = new CartItem
        {
            CartItemId = Guid.NewGuid().ToString(),
            ProductId = id,
            CartId_ = ShoppingCartId,
            Product = temp,
            Quantity = 1,
        };

        new BLFrontend().addCartItem(cartItem);//The problem starts from here
    }
    else
    {
        cartItem.Quantity++;
        //update
    }

我在我的项目中使用 EF,这是模型:

namespace BusinessEntitys
{
using System;
using System.Collections.Generic;

public partial class CartItem
{
    public string CartItemId { get; set; }
    public string CartId_ { get; set; }
    public int Quantity { get; set; }
    public int ProductId { get; set; }

    public virtual Product Product { get; set; }
}
}

class CratItem 中包含的产品:

    namespace BusinessEntitys
    {
    using System;
    using System.Collections.Generic;
    using System.Linq; // added this

    public partial class Product
    {
        public Product()
        {
            this.ItemInOrders = new HashSet<ItemInOrder>();
            this.CartItems = new HashSet<CartItem>();
        }

        public int ProductId { get; set; }
        public string ProductName { get; set; }
        public double ProductBasePrice { get; set; }
        public double ProductDiscount { get; set; }
        public string ProductDescription { get; set; }
        public string ProductImageURL { get; set; }
        public string ProductQualityLevel { get; set; }
        public string ProductCategory { get; set; }

        public virtual ICollection<CartItem> CartItems { get; set; }
    }
}

我的 BusinessEntity 是:

namespace BusinessEntitys
{
    using System;
    using System.Data.Entity;
    using System.Data.Entity.Infrastructure;

    public partial class StoreDBEntities : DbContext
    {
        public StoreDBEntities()
            : base("name=StoreDBEntities")
        {
            base.Configuration.ProxyCreationEnabled = false;
        }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            throw new UnintentionalCodeFirstException();
        }

        public virtual DbSet<Client> Clients { get; set; }
        public virtual DbSet<ItemInOrder> ItemInOrders { get; set; }
        public virtual DbSet<Order> Orders { get; set; }
        public virtual DbSet<Product> Products { get; set; }
        public virtual DbSet<StockManagment> StockManagments { get; set; }
        public virtual DbSet<CartItem> CartItems { get; set; }
    }
}

尝试执行命令时,我的 DAL 中的第二行出现异常: context.CartItems.Add(CartItemToAdd)

 public bool addCartItem(CartItem CartItemToAdd)
        {
            try
            {
                var context = new StoreDBEntities();
                context.CartItems.Add(CartItemToAdd);
                return context.SaveChanges() > 0;

            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }

stackTracer:

StackTrace "at DataAccess.Dal.addCartItem(CartItem CartItemToAdd) in c:\Users\User\Documents\Visual Studio 2013\Projects\OrGarden\DataAccess\Dal.cs:line 406\r\n at BusinessLogicBackend.BLBackend.addCartItem(CartItem cartItemToAdd) in c:\Users\User\Documents\Visual Studio 2013\Projects\OrGarden\BusinessLogicBackend\BLBackend.cs:line 293\r\n at SyncInvokeaddCartItem(Object , Object[] , Object[] )\r\n at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs)\r\n at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)" string

重要更新:当我删除此作业时 Product = temp, addCartItem 调用成功保存,没有问题。只有字段 Product 保持 null。 更改后的代码:

Product temp =  business.getAllProducts().SingleOrDefault(
                     p => p.ProductId == id);
                // Create a new cart item if no cart item exists.                 
                cartItem = new CartItem
                {
                    CartItemId = Guid.NewGuid().ToString(),
                    ProductId = id,
                    CartId_ = ShoppingCartId,
                    Product = temp,
                    Quantity = 1,
                };

                 business.addCartItem(cartItem);

当我从上下文中检索到 CrartItem 时,字段 Product 仍然是 null

谁能帮我解决那个坏问题?

非常感谢, 罗恩

首先,如果你愿意,我强烈建议你看看Unit of Work pattern (MSDN version

问题是,您每次都在创建 BLFrontEndStoreDBEntities 的新实例。似乎没有理由这样创建实例。

我不确定 BLFrontEnd 内部到底发生了什么,但我敢打赌 BLFrontEnd 上的每个方法也会创建一个新的 StoreDBEntities 实例。这可能是异常的原因。

您需要管理实例的生命周期。看看这个:

public void AddToCart(int id)
{
    // Begins new life-cycle of BLFrontend
    var frontend = new BLFrontend();
    // or you can wrap it using statement.
    // using(var frontend = new BLFrontend())
    // {
    //    ... code ...
    // }

    // Retrieve the product from the database.           
    ShoppingCartId = GetCartId();

    CartItem cartItem = frontend.getAllCartItems().SingleOrDefault(
         c => c.CartItemId == ShoppingCartId
         && c.ProductId == id);
    if (cartItem == null)
    {
        Product temp = frontend.getAllProducts().SingleOrDefault(
             p => p.ProductId == id);
        // Create a new cart item if no cart item exists.                 
        cartItem = new CartItem
        {
            CartItemId = Guid.NewGuid().ToString(),
            ProductId = id,
            CartId_ = ShoppingCartId,
            Product = temp,
            Quantity = 1,
        };

        frontend.addCartItem(cartItem);//The problem starts from here
    }
    else
    {
        cartItem.Quantity++;
        //update
    }

    // end of life-cycle of the instance.
    frontend.Dispose();
}


public class BLFrontEnd : IDispose
{
    private readonly StoreDBEntities dbContext;
    public BLFrontEnd()
    {
        dbContext = new StoreDBEntities();
    }

    public void Dispose()
    {
        dbContext.Dispose();
    }

    public IQueryable<Cart> getAllCartItems()
    {
       // your logics...
       return dbContext.Carts.AsQueryable();
    }

    public IQueryable<Product> getAllProducts()
    {
       // your logics...
       return dbContext.Products.AsQueryable();
    }

    public bool addCartItem(CartItem CartItemToAdd)
        {
            try
            {
                //var context = new StoreDBEntities();
                dbContext.CartItems.Add(CartItemToAdd);
                return context.SaveChanges() > 0;

            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }
}

如您所见,'A work' 开始于 AddToCart() 方法的头部,结束于方法的尾部。那就是 'A work' 的生命周期。在生命周期中,每个资源都处于相同的上下文中。这意味着生命周期中的每个代码都将使用相同的资源实例。它避免了不必要的新实例创建。

这段代码不是很好,您需要重构以满足您的用例和架构。但我希望你明白了。

已编辑

好的,为了将实际问题与您的 BL 分开,您可以试试这个:

public void AddToCart(int id)
{
    // use StoreDBEntities directly, instead of BLFrontend.
    using(var dbContext = new StoreDBEntities())
    {
        // Retrieve the product from the database.           
        ShoppingCartId = 123; // use magic number for this test.

        // and use dbContext directly.
        CartItem cartItem = dbContext.Carts.SingleOrDefault(
             c => c.CartItemId == ShoppingCartId
             && c.ProductId == id);
        if (cartItem == null)
        {
            Product temp = dbContext.Products.SingleOrDefault(
                 p => p.ProductId == id);
            // Create a new cart item if no cart item exists.                 
            cartItem = new CartItem
            {
                CartItemId = Guid.NewGuid().ToString(),
                ProductId = id,
                CartId_ = ShoppingCartId,
                Product = temp,
                Quantity = 1,
            };

            dbContext.Carts.Add(cartItem);
        }
        else
        {
            cartItem.Quantity++;
            //update
        }

        dbContext.SaveChanges();
    }
}