商品、訂單、購物車和訂單商品快照的關係,初步瞭解成為架構師的思想
導讀
最近見同事在做訂單和訂單材料快照這方面的業務,這其實就像淘寶上的商品,不過,這裡是材料了。它一共涉及到 五 張表:
- 材料表,材料()的詳細資訊
- 訂單表,使用者購買商品下單時
- 購物車,待付款材料
- 使用者表,誰購買了了材料
- 訂單材料快照表,這就是訂單和材料的快照
因而,這裡面就涉及到一對一的關係。
一對一的關係
雖然一對一的關係用的不多,但我們有時也會設計這方面的資料表,不常用不代表不用。
我們一般做分表會使用一堆的關係,比如說使用者表和使用者快照表。使用者表儲存使用者必填的資訊,碧如 賬號、性別、密碼、登入時間、退出時間等等。使用者擴充套件表就是使用者的擴充套件資訊,比如愛好、暱稱、等等。是使用者可填可不填的。如果資料都放在同一張表中,會感覺比較亂的。如程式碼所示:
使用者表的部分資料
@Entity @Table(name = "core_user") public class User { /** * 使用者名稱,唯一 */ @NotEmpty(message = "使用者名稱不能為空") @Column(length = 100, unique = true, nullable = false) private String username; /** * 密碼 */ @Column(nullable = false, length = 66) private String password; /** * 使用者擴充套件表 */ @OneToOne(mappedBy = "user", fetch = FetchType.LAZY, cascade = CascadeType.ALL) private UserExt userExt; 。。。。 }
使用者擴充套件表的部分資料
@Entity @Table(name = "core_user_ext") public class UserExt implements Serializable { @OneToOne @PrimaryKeyJoinColumn private User user; /** * 自我介紹 */ @Lob @Basic(fetch = FetchType.LAZY) @Column(name = "introduce", columnDefinition = "text") private String introduce; /** * 性別 */ @Enumerated(EnumType.STRING) @Column(name = "gender", length = 20) private GenderEnum gender; /** * 暱稱 */ @Column(name = "nick_name", length = 66) private String nickName; /** * 真實姓名 */ @Column(name = "real_name", length = 100) private String realName; /** * 頭像 */ @ManyToOne @JoinColumn(name = "head_image") private Picture headImage; /** * 聯絡地址 */ @Column(name = "address", length = 200) private String address; /** * 郵政編碼 */ @Column(name = "postal_code") private String postalCode; @Column(name = "qq", length = 66) private String qq; /** * 身高 */ @Column(length = 3) private Integer height; /** * 喜歡的運動 */ @Column(name = "loved_sports", length = 255) private String lovedSports; /** * 喜歡的電影 */ @Column(name = "loved_movies", length = 255) private String lovedMovies; /** * 喜歡的音樂 */ @Column(name = "loved_musics", length = 255) private String lovedMusics; /** * 喜歡的食物 */ @Column(name = "loved_foods", length = 255) private String lovedFoods; /** * 喜歡的書 */ @Column(name = "loved_books", length = 255) private String lovedBooks; /** * 喜歡的遊戲 */ @Column(name = "loved_games", length = 255) private String lovedGames; }
使用者擴充套件資訊是使用者的輔助資訊,它們適合一對一的關係。
詳解客戶材料(商品)、使用者材料(商品)、訂單、購物車、使用者、和訂單商品快照
- 使用者,是誰購買了這個商品,這時我們需要知道的。
- 材料商材料(材料商的商品),因為,我們這個平臺主要是售賣裝修材料的,其分為兩部分。一部分是材料商在平臺上掛出他們的材料,材料商下的經銷商購買材料。他們購買材料後,這就涉及另一部分,即經銷商掛出他們的材料。這個時候才賣給使用者,因而,對於經銷商來說,還要有一個市場零售價。
- 經銷商材料(經銷商的商品):正如上面所說,我是經銷商,從總代理那邊購買了產品,然後,在我的這部分平臺上售賣,此時,使用者從我這邊購買了,然後將其加入到購物車中。
- 訂單,即為我們在購買裝修材料時所生成的一條購買記錄。
- 購物車,即為我們已經選好了商品,暫時還沒有進行付款,只是暫存起來,這也是一條記錄。等我們付款的時候,就從購物車中付款了。
- 訂單快照,比如我們昨天購買的商品材料,其當時的零售價是25元,但今天就變成了40元,等我們拿到手後,感覺不大合適,於是,申請退還裝修材料。此時我們在網頁上看到的材料價格是40元,而我們付款的時候是25元。商家是退給我們多少錢呢?25元,還是40元?當然,是25元,而不是40元。這25元儲存在哪裡呢?就是訂單快照表。我們在付款的那一刻,或者,不管是直接購買的付款,還是從購物車中的購買,就會生成一條訂單材料快照表。快照表有哪些資訊:一個購物車的外來鍵,訂單的外來鍵,裝修材料的中必須讓使用者知道的資訊等。 裝修材料從某種意義上來說,其也是一種一對一的關係,商品和快照找那個所儲存的主要的材料資訊。
所有的資訊,如以下程式碼,不重要的或設計公司機密的資訊,就不在這裡展示了。
使用者表
這裡使用者可以為分材料商和經銷商,通過這個列舉類CustomerTypeEnum確定的。材料商和經銷商放在同一張表中,根據他們的型別,來確認是材料商和經銷商。
@Entity @Table(name = "core_user") public class User{ /** * 使用者名稱,唯一 */ @NotEmpty(message = "使用者名稱不能為空") @Column(length = 100, unique = true, nullable = false) private String username; /** * 密碼 */ @Column(nullable = false, length = 66) private String password; /** * 最近登入ip */ @Column(name = "last_login_ip", length = 64) private String lastLoginIP; 。。。。
材料商材料
因為材料商是一個實體,我們這裡只要關聯材料商的外來鍵即可,而且還是一對多的關係。因為,材料表中某一個材料商的記錄不止一條。其次,還要有材料型別,材料型別表是樹結構的,型別下面還有子型別。這裡也是一對多的關係。
public class Material extends BaseObj { /** * 所屬品類 */ @ManyToOne @JoinColumn(name = "material_category_id") private MaterialCategory materialCategory; /** * 名稱 */ private String name; /** * 供應商 */ @ManyToOne @JoinColumn(name = "supplier_id") private Supplier supplier; /** * 品牌 */ @ManyToOne @JoinColumn(name = "material_brand_id") private MaterialBrand materialBrand; /** * 成本價 */ @Column(name = "cost_price", precision = 12, scale = 2) private BigDecimal costPrice; /** * 零售價 */ @Column(name = "retail_price", precision = 12, scale = 2) private BigDecimal retailPrice; /** * 單位 */ @ManyToOne @JoinColumn(name = "unit_code") private DataDict unit; 。。。 }
經銷商材料
經銷商從材料商那邊購買了材料,經銷商的材料即來源於材料這張表。因而,這個經銷商材料只要關聯材料表即可。同時,還要有確認經銷商是哪個經銷商,因而,需要一個使用者的外來鍵,即經銷商材料的所有者。經銷商有自己的定價規則,他需要定義一個市場價。
public class UserMaterial extends BaseObj { /** * 材料 */ @ManyToOne @JoinColumn(name = "material_id") private Material material; /** * 所有者 */ @ManyToOne @JoinColumn(name = "owner_id") private User owner; /** * 市場價 */ @Column(name = "market_price", precision = 12, scale = 2) private BigDecimal marketPrice; 。。。 }
訂單
我們從經銷商那邊購買了材料,此時,有條購買記錄,這就是訂單。誰發起的訂單,也就是說,誰購買的這個材料,因而,需要使用者的外來鍵。
public class Order extends BaseObj { /** * 收貨地址 */ @ManyToOne @JoinColumn(name = "work_site_id") private WorkSite workSite; /** * 訂單編號 */ @Column(name = "order_no") private String orderNo; /** * 訂單狀態 */ @Enumerated(EnumType.STRING) private OrderStatusEnum status; /** * 訂單備註 */ @Column(name = "remark", columnDefinition = "longtext") private String remark; /** * 下單時間 */ @Column(name = "generate_time") private Date generateTime; /** * 提交時間 */ @Column(name = "submit_time") private Date submitTime; /** * 買家 */ @ManyToOne @JoinColumn(name = "buyer_id") private User buyer;
購物車
我們已經選好了材料,但還沒有確認付不付款,於是,先在購物車存著,想起來就付款。加入到購物車的材料時經銷商的材料,因而,購物車需要儲存經銷商的外來鍵。同時,還要確認是誰加入的購物車,因而購物車需要使用者的外來鍵。這都是一對多的關係。同時,需要確認,這個購物車是否被使用。
public class ShoppingCart extends BaseObj { /** * 使用者材料 */ @ManyToOne @JoinColumn(name = "user_material_id") private UserMaterial userMaterial; /** * 數量 */ @Column(name = "num", precision = 12, scale = 2) private Double num = 1.0; /** * 金額 */ @Column(name = "amount", precision = 12, scale = 2) private BigDecimal amount; /** * 所有者 */ @ManyToOne @JoinColumn(name = "owner_id") private User owner; /** * 是否被使用 */ @Enumerated(EnumType.STRING) @Column(name = "is_used") private BooleanEnum isUsed = NO; }
訂單材料快照表
這裡,我們只要儲存訂單快照的id,而不是訂單快照的物件?為什麼呢?首先,對於使用者來說,購買裝修材料時,這個購物車是不常用的,因為,他們一旦看中了,就會直接購買的。其次,如果我們儲存的是物件,使用者每次載入購物車時,都要從資料庫中遍歷當前id的購物車的資料庫的欄位值,然後通過hibernate的反射封裝到購物車的物件中。所以說呢,無疑是減緩了效率,這樣不好。
需要訂單的外來鍵,訂單和訂單快照雖然是一對一的關係,一個訂單一個訂單快照。也就是說,當用戶生成訂單時,就會有個訂單快照。使用者檢視其購買記錄(訂單記錄)的材料資訊時,材料資訊不是來源於使用者材料表,而是來源於使用者訂單快照表。還有,使用者退還材料時,經銷商要檢視使用者當前購買的材料資訊。這就用到了訂單材料快照表。
public class OrderMaterialSnapshot extends BaseObj { /** * 購物車id */ @Column(name = "shopping_cart_id") private Long shoppingCartId; /** * 訂單 */ @ManyToOne @JoinColumn(name = "order_id") private Order order; /** * 狀態 */ @Enumerated(EnumType.STRING) @Column(name = "status") private OrderMaterialStatusEnum status; /** * 購買數量 */ @Column(name = "num", precision = 12, scale = 2) private Double num = 1.0; /** * 退貨數量 */ @Column(name = "refund_num") private Double refundNum = 0.0; /** * 購買總金額 */ @Column(name = "amount", precision = 12, scale = 2) private BigDecimal amount; /** * 接單時間 */ @Column(name = "receive_time") private Date receiveTime; /** * 發貨時間 */ @Column(name = "deliver_time") private Date deliverTime; /** * 收貨時間 */ @Column(name = "receipt_time") private Date receiptTime; /** * 所屬品類 */ @ManyToOne @JoinColumn(name = "material_category_id") private MaterialCategory materialCategory; /** * 名稱 */ private String name; /** * 品牌 */ @OneToOne @JoinColumn(name = "material_brand_id") private MaterialBrand materialBrand; /** * 型號 */ private String model; /** * 零售價 */ @Column(name = "retail_price", precision = 12, scale = 2) private BigDecimal retailPrice; /** * 會員單價(材料商零售價*會員折扣) */ @Column(name = "vip_unit_price", precision = 12, scale = 2) private BigDecimal vipUnitprice; /** * 市場價 */ @Column(name = "market_price", precision = 12, scale = 2) private BigDecimal marketPrice; /** * 單位 */ @ManyToOne @JoinColumn(name = "unit_code") private DataDict unit; 。。。 }
總結
要想稱為優秀的架構師,首先參考別人的架構,畢竟,他山之石,可以攻玉嗎!!!
再接再厲,致奮鬥的自己!!!