NHibernate系列之四_繼承Table Per Class

  • 2214
  • 0

摘要:繼承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'