摘要:繼承Table Per Class
假設系統有一個Order、OrderDetail、ProductDesc的類別關係如下
因為需求增加,所以Order在結帳時可以使用信用卡消費,但必須加收一成服務費。為此在Order加開欄位IsCreditCard,然後來修改程式,判斷是否為信用卡消費。
class Order
{
public void ReCalcualte
{
if(IsCreditCard == false)
SumAmount = 所有OrderDetail的Price * Unit
else
SumAmount = 所有OrderDetail的Price * Unit * 1.1
}
}
假設將來結帳方式增加了,bit欄位不夠用,就會變成int或varchar,ReCalcualte也會更加複雜,所以我用繼承來試著處理這個問題。 NH中處理繼承的手法很多,就先從Table Per Class著手。首先我想把信用卡消費分開成一個CreditCardOrder,CreditCardOrder內容如下
public class CreditCardOrder : Order
{
public virtual decimal DiscountAmount { get; set; }
public override void ReCalculate()
{
base.ReCalculate();
SumAmount = SumAmount + SumAmount*0.1m;
DiscountAmount = SumAmount*0.1m;
}
}
Order的Mapping的設定如下
所謂的Table Per Class是運用一個欄位的值做判斷,決定子類別的類型,這個例子中,discriminator中指定了IsCreditCard這個欄 位,discriminator-value="Y"告訴我們如果欄位是Y,會回傳CreditCardOrder物件,若為null,則會傳Order 物件。discriminator除了string型別外,也可以指定int,可是卻不能為null,也就是每列都對應一種子類別。
現在各建立一個Order物件與一個CreditCardOrder物件
Order order = new Order();
order.ShoppingDate = new DateTime(2011, 7, 14);
ProductDesc productDesc = new ProductDesc();
productDesc.Name = "原子筆";
productDesc.Price = 13;
OrderDetail orderDetail = new OrderDetail();
orderDetail.Quantity = 20;
orderDetail.SellPrice = 10;
orderDetail.SellProductDesc = productDesc;
order.AddDetail(orderDetail);
--------------------------------------------------------------
CreditCardOrder creditCardOrder = new CreditCardOrder();
creditCardOrder.ShoppingDate = new DateTime(2011, 7, 14);
ProductDesc productDesc = new ProductDesc();
productDesc.Name = "鉛筆";
productDesc.Price = 8;
OrderDetail orderDetail = new OrderDetail();
orderDetail.Quantity = 20;
orderDetail.SellPrice = 10;
orderDetail.SellProductDesc = productDesc;
creditCardOrder.AddDetail(orderDetail);
來看看查詢的結果
IList<[order]> orders = session.CreateCriteria<[order]>().List<[order]>();
//雖然是查Order,但連CreditCardOrder也會查出
foreach (Order order in orders)
{
order.ReCalculate();
}
Assert.AreEqual(200, orders[0].SumAmount);
Assert.AreEqual(220, orders[1].SumAmount);
換個方式查詢,只會取出一筆資料
IList<[creditcardorder]> orders = session.CreateCriteria<[creditcardorder]>().List<[creditcardorder]>();
foreach (Order order in orders)
{
order.ReCalculate();
}
Assert.AreEqual(1, orders.Count);
Assert.AreEqual(220, orders[0].SumAmount);
查詢語法如下,這似乎讓我們想到有多常寫這種SQL,不如考慮用繼承來解決。
SELECT this_.OrderNo as OrderNo8_0_, this_.ShoppingDate as Shopping3_8_0_, this_.SumAmount as SumAmount8_0_, this_.DiscountAmount as Discount5_8_0_ FROM [Order] this_ WHERE this_.IsCreditCard='Y'