導讀
最近見同事在做訂單和訂單材料快照這方面的業務,這其實就像淘寶上的商品,不過,這裏是材料了。它一共涉及到 五 張表:
- 材料表,材料()的詳細信息
- 訂單表,用戶購買商品下單時
- 購物車,待付款材料
- 用戶表,誰購買了了材料
- 訂單材料快照表,這就是訂單和材料的快照
因而,這裏面就涉及到一對一的關係。
一對一的關係
雖然一對一的關係用的不多,但我們有時也會設計這方面的數據表,不常用不代表不用。
我們一般做分表會使用一堆的關係,比如說用戶表和用戶快照表。用戶表存儲用戶必填的信息,碧如 賬號、性別、密碼、登錄時間、退出時間等等。用戶擴展表就是用戶的擴展信息,比如愛好、暱稱、等等。是用戶可填可不填的。如果數據都放在同一張表中,會感覺比較亂的。如代碼所示:
用戶表的部分數據
@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;
。。。
}
總結
要想稱爲優秀的架構師,首先參考別人的架構,畢竟,他山之石,可以攻玉嗎!!!
再接再厲,致奮鬥的自己!!!