【问题标题】:Unable to set field/property CartItems on entity type BusinessEntitys.Product无法在实体类型 BusinessEntitys.Product 上设置字段/属性 CartItems
【发布时间】:2015-05-27 22:02:07
【问题描述】:

我花了很多时间(包括广泛的 Google 搜索)试图找出问题所在。不幸的是,没有成功。 我得到的错误是:“无法在实体类型 BusinessEntitys.Product 上设置字段/属性 CartItems。有关详细信息,请参阅 InnerException。” innerExeptionnull。 当我尝试通过 WCF 调用函数 addCartItem 时,addToCart() 函数发生错误。当调用到达 DAL 并尝试将新对象保存在 db 上下文中时,它失败了。

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; }
}
}

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; }
    }
}

我的业务实体是:

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 中的第 2 行执行: 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);
            }
        }

堆栈跟踪器:

StackTrace "在 DataAccess.Dal.addCartItem(CartItem CartItemToAdd) 中 c:\Users\User\Documents\Visual Studio 2013\Projects\OrGarden\DataAccess\Dal.cs:406 行\r\n 在 BusinessLogicBackend.BLBackend.addCartItem(CartItem cartItemToAdd) 在 c:\Users\User\Documents\Visual Studio 2013\Projects\OrGarden\BusinessLogicBackend\BLBackend.cs:line 293\r\n 在 SyncInvokeaddCartItem(Object , Object[] , Object[] )\r\n 在 System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(对象 实例,Object[] 输入,Object[]& 输出)\r\n at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)" 字符串

重要更新:当我删除此分配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

谁能帮我解决这个糟糕的问题?

非常感谢, 罗恩

【问题讨论】:

  • 第一个问题是,恕我直言,您正在混合 2 个上下文:可能一个在 BLFrontend().getAllProducts() 另一个在 BLFrontend().addCartItem(cartItem)
  • 错误似乎context 没有 CartItems 属性。 (您的代码似乎也证实了这一点,尽管我看不到 DbContext 类)。如果您使用StoreDBEntities context 而不是var context,智能感知应该会向您指出这一点。
  • @tschmit007 如果两个上下文出错,我必须更改什么?在 Dal 中 getAllProducts() 的代码是:public List&lt;Product&gt; getAllProducts() { try { List&lt;Product&gt; ls = new StoreDBEntities().Products.ToList(); return ls; } catch (Exception ex) { throw new Exception(ex.Message); } }
  • @HW 您可以在上面的 BusinessEntitys 中看到 CartItems 属性。我也试过你的建议,不幸的是它没有解决我的问题。谢谢!
  • 上下文实例不应该是方法的一部分,而是(例如)类的构造函数

标签: c# asp.net entity-framework wcf ado.net


【解决方案1】:

首先,我强烈建议您查看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() 方法的头部,结束于方法的尾部。这就是“作品”的生命周期。在生命周期中,每个资源都处于相同的上下文中。这意味着生命周期中的每个代码都将使用相同的资源实例。它避免了不必要的新实例的创建。

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

已编辑

好的,把实际问题与你的 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();
    }
}

【讨论】:

  • @Gongado Gong 非常感谢您的回复。我浏览了代码并根据您的解释进行了更改。不幸的是,它并没有解决问题。另一个建议可能吗?
  • @Roni 基本上,例外是您同时混合 2 个 DbContext 实例,正如 tschmit007 所说。我编辑了我的答案。它解决了你的问题吗?
  • @GongadoGong 感谢您的更新!!!我尝试按照您的建议进行更改以进行测试,幸运的是它运行良好。现在,我必须通过前端工作 - 这意味着通过 WCF 工作。我们的要求是通过以 Frontend 为代表的 WCF Service 来做到这一点。如何管理其实例化的生命周期?谢谢!!!
  • @Roni 我很高兴来到这里!管理对象生命周期的方法有很多。这将是一个漫长的故事。好吧,没有一个简单的答案完全适合你。但本质上还有一些与这些情况相关的设计模式和原则,例如 UoW(工作单元)、IoC(控制反转)、DI(依赖注入)等。如果您的时间用完了,只需像上面那样简化您的前端代码。然后花点时间了解这些模式并将其应用到您的代码中。希望对你有帮助。
猜你喜欢
  • 2013-04-25
  • 1970-01-01
  • 2010-12-04
  • 2013-07-05
  • 1970-01-01
  • 2021-12-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多