这不是一个技术问题,而是一个关于如何对数据建模的问题。
首先,我使用实体框架来构建数据存储。
我一直在为一家小企业创建一个电子商务网站,我创建了一个似乎可以正常工作的系统,但我现在意识到我犯了一个根本性的错误(我认为!)。
我有一个订单对象和一个产品对象。该产品显然包含了产品的所有细节,包括价格。
我现在已经创建了100多个产品,这些产品现在放在一张名为产品的桌子上
因此,当我创建订单时,会将单个产品或多个产品添加到订单中。因此,订单现在包含对products表的引用。
这很好,直到我意识到我可能想更改订单中产品的价格(提供折扣等)。由于订单中的产品与产品表绑定,如果我更改价格,它将更改所有以前和即将发布的订单的价格。
所以看起来我需要两张产品表。一个是当前待售的产品列表,另一个是作为订单对象的子级的已售出产品列表。
最好的建模方法是什么?我确信我需要两张不同的产品表。
如能就此提供任何指导,我们将不胜感激。
为什么不创建一个捕获实际支付价格的订单项目实体?这样做是相当标准的。
有多种方法可以实现这一点——确切地说,您想要实现什么与复杂性将决定哪种解决方案最适合您。
就我个人而言,我不会让我的订单链接直接(如果有的话)到产品。我的订单将由订单行组成,其中包含描述、单价、数量等。如果您想启用导航或链接回产品,我会在订单行上添加产品链接。产品的价格从未纳入订单成本的计算,它只是在订购时复制到订单行,并应用任何折扣/修改。在不影响任何产品或其他订单的情况下,您可以安全地修改订单行。订单行将只与单个订单相关。
我假设产品和订单之间的联系是多对多?如果链接表是这样的话(这可能意味着你必须首先在实体框架代码中手动指定一个交集表),你可以添加一个价格转换属性。这可能只是一个百分比-100%没有变化90%折扣等
你可以将定价与产品完全分开,然后根据你想制造的复杂程度,为特定用户、用户组甚至订购的数量的产品指定给定的价格。然而,这可能需要做很多工作,听起来不像是你需要的。
此外,尽管我可能不想这样做,但你可以让每个产品条目都是不可变的(它永远不会改变),并且可以通过创建一个新记录来模拟变化,然后将原始或新创建的产品标记为"隐藏"(因为没有更好的术语),并且通常无法访问。在提供产品折扣的情况下,你会修改链接到订单的产品,而在幕后,它真正要做的是创建一个新的"隐藏"产品,上面有新的价格。你必须在查看产品页面上处理这个问题,以检测产品的状态并相应地处理它。如果使用了订单历史记录页面,并允许导航到您给予一次性折扣的产品,则您需要确保您的应用程序不允许以该价格再次订购。
您可以拥有如下表/实体:
Product (ProductId, ProductName, ProductDescription, Price, ...)
Order (OrderId, DateTime, ...)
OrderItem (OrderItemId, OrderId, ProductId, Price, Quantity, ...)
如果需要,你也可以有一个股票表。
对于您的解决方案,我将执行以下模型
public class Product
{
public int Id { get; set; }
public double Price { get; set; }
public bool Archived { get; set; }
}
public class OrderProduct
{
public int Id { get; set; }
public Order Order { get; set; }
public Product Product { get; set; }
public double Price { get; set; }
public int Total { get; set; }
}
public class Order
{
public int Id { get; set; }
public int UserId { get; set; }
public List<OrderProduct> Products { get; set; }
public Discount Discount { get; set; }
public DateTime CreatedAt { get; set; }
}
public class Discount
{
public int Id { get; set; }
public DiscountType Type { get; set; }
public string Code { get; set; }
public double Amount { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public List<Product> ProductsToApply { get; set; }
public List<Product> RequiredProducts { get; set; }
}
public enum DiscountType
{
Amount,
Percent
}
产品-我认为无需解释
折扣-如果您需要降价,那么是的,您应该在产品上进行更改。但有了折扣,你就更容易受到攻击了,因为你可以只为特定的产品创建限时优惠,你也可以添加所需的产品来购买以获得折扣但为了解决您的主要问题,我会在两个表中完成,order和OrderProduct,我会保存客户购买的商品数量和价格。
订单-如果客户购买了产品,那么您将创建订单,并根据产品及其当前价格将OrderProducts添加到订单中。如果有,也要订购,请附上折扣
上个月我在一个电子商务网站上工作时也遇到过类似的情况。我使用了类似的方法(正如Rob West和Allan所建议的),每个订单都有多个OrderItem。每个OrderItem都有一个到Product的链接,但除了它之外,它还有两个额外的字段,ItemCost、Discount和SubTotal。
在创建订单时,我会将产品的价格复制到OrderItem中,然后应用折扣。
此外,我在订单表上有一个GroupDiscount列,可以为整个订单提供集体折扣。
这在生产中一直运行良好,没有任何问题。
没有必要,而是有两个产品表的冗余。您需要的是订单表中的一个额外字段,指定每种产品的销售单价。在一天结束时,当你想计算你的资金流时,你应该参考订单表中设定的单价。
为了进一步开发,您可能需要一个产品价格的历史记录表。这样你就可以回顾历史来分析价格调整。
通常,您要做的是有一个名为OrderProduct
的表或任何您想调用的表,然后该表将有任何必须在下单后及时冻结的内容。你的实体最终会是这样的:
public class Product
{
public int Id {get; set;}
public string ProductName {get; set;}
public virtual ICollection<OrderProduct> OrderProducts {get; set;}
}
public class Order
{
public int Id {get; set;}
public virtual ICollection<OrderProduct> OrderProducts {get; set;}
}
public class OrderProduct
{
public int Id {get; set;}
public virtual Order Order {get; set;}
public virtual Product Product {get; set;}//this is optional,
//you would only include it if you need to query
//other information about the product
//that wouldn't change (color, size, type, etc.)
}
您可以使用另一种方法。试着将价格(和历史变化)存储在单独的表格中。
简单地说,创建表ProductPrice(ProductId,Price,StartDate)并将其用于所有价格更改。OrderItem应该引用ProductPrice而不是Product。对于每个新订单,获取最后价格(按开始日期)。
对于自定义的OrderItem操作(vip客户的折扣、交付的额外成本等),请在OrderItem表中创建字段。如果有许多不同的因素影响价格,请创建单独的表格。例如,PriceModification(修改规则列表)和PriceModificationInOrderItem。
有关更多信息,请参阅如何在关系理论中创建历史表。例如本文:http://database-programmer.blogspot.ru/2008/07/history-tables.html
只需将PricePaid
字段添加到OrderItem
表中。价格可能会变化,但订单仍然存在。