zoukankan      html  css  js  c++  java
  • 解读Petshop3.2用Nhibernate重构系列(四)

    这一节,我们来讲述如何实现一个一对多对象的操作。很显然的,在PetShop中最显著的就是Order和LineItem之间的关系了。
    我们应该把Order对象和LineItem对象的保存处理在一个事务中。
    在这一节,他利用了通过一个回调函数提供一个事务环境(TransHelper.cs)。
    首先我们看看这些配置文件
    <?xml version="1.0" encoding="utf-8" ?>
    <hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">
        
    <class name="PetShop.BLL.Order, PetShop.BLL" table="Orders">
            
    <id name="OrderId" column="OrderId" type="Int32" unsaved-value="0" access="nosetter.camelcase-underscore">
                
    <generator class="native"/>
            
    </id>
            
    <property type="String" length="20" name="UserId" column="UserId" not-null="true"/>
            
    <property type="DateTime" not-null="true" column="OrderDate" name="Date"/>
            
    <component name="CreditCard" class="PetShop.BLL.CreditCard, PetShop.BLL">
                
    <property name="CardNumber" type="String" length="20" column="CreditCard" not-null="true"/>
                
    <property name="CardExpiration" column="ExprDate" type="String" length="7" not-null="true"/>
                
    <property name="CardType" column="CardType" length="40" not-null="true" type="String"/>
            
    </component>
            
    <component name="BillingAddress" class="PetShop.BLL.Address, PetShop.BLL">
                
    <property name="Address1" column="BillAddr1" type="String" length="80" not-null="true"/>
                
    <property name="Address2" column="BillAddr2" type="String" length="80" not-null="false"/>
                
    <property name="City" column="BillCity" type="String" length="80" not-null="true"/>
                
    <property name="State" column="BillState" type="String" length="80" not-null="true"/>
                
    <property name="Zip" column="BillZip" type="String" length="20" not-null="true"/>
                
    <property name="Country" column="BillCountry" type="String" length="20" not-null="true"/>
                
    <property name="FirstName" column="BillToFirstName" type="String" length="80" not-null="true"/>
                
    <property name="LastName" column="BillToLastName" type="String" length="80" not-null="true"/>
            
    </component>
            
    <component name="ShippingAddress" class="PetShop.BLL.Address, PetShop.BLL">
                
    <property name="Address1" column="ShipAddr1" type="String" length="80" not-null="true"/>
                
    <property name="Address2" column="ShipAddr2" type="String" length="80" not-null="false"/>
                
    <property name="City" column="ShipCity" type="String" length="80" not-null="true"/>
                
    <property name="State" column="ShipState" type="String" length="80" not-null="true"/>
                
    <property name="Zip" column="ShipZip" type="String" length="20" not-null="true"/>
                
    <property name="Country" column="ShipCountry" type="String" length="20" not-null="true"/>
                
    <property name="FirstName" column="ShipToFirstName" type="String" length="80" not-null="true"/>
                
    <property name="LastName" column="ShipToLastName" type="String" length="80" not-null="true"/>
            
    </component>
            
    <property name="OrderTotal" type="Decimal" column="TotalPrice" not-null="true"/>
            
    <property name="Courier" type="String" column="Courier" not-null="true" length="80" access="field.camelcase-underscore"/>
            
    <property name="Locale" type="String" column="Locale" not-null="true" length="20" access="field.camelcase-underscore"/>
            
    <bag name="LineItems" access="nosetter.camelcase-underscore" inverse="true" cascade="save-update">
                
    <key column="OrderId"/>
                
    <one-to-many class="PetShop.BLL.CartItem, PetShop.BLL"/>
            
    </bag>
            
    <one-to-one name="Status" class="PetShop.BLL.OrderStatus, PetShop.BLL" cascade="save-update"/>
        
    </class>
    </hibernate-mapping>
    包含了属性/组件/bag :)我只是知道大概,但是不知道怎么表达,没什么仔细研究:)
    最重要的是bag--它可以用来指定一个一对多的关系。

    接着我们来看接口
    using System;

    //References to PetShop specific libraries
    //PetShop busines entity library
    using PetShop.BLL;

    namespace PetShop.IDAO{
        
    /// <summary>
        
    /// Interface for the Order DAL
        
    /// </summary>

        public interface IOrderDAO{
            
    /// <summary>
            
    /// Method to insert an order header
            
    /// </summary>
            
    /// <param name="order">Business entity representing the order</param>

            void Insert(Order order);

            
    /// <summary>
            
    /// Reads the order information for a given orderId
            
    /// </summary>
            
    /// <param name="orderId">Unique identifier for an order</param>
            
    /// <returns>Business entity representing the order</returns>

            Order GetOrder(int orderId);
        }

    }

     
        这里定义了新增订单/根据订单ID获取订单的操作规范。
    同时我们还需要看看IInventoryDAO接口

    using System;

    using PetShop.BLL;

    namespace PetShop.IDAO{
        
    /// <summary>
        
    /// Interface for the Inventory DAL
        
    /// </summary>

        public interface IInventoryDAO{
            
    /// <summary>
            
    ///  Reduces the stock level by the given quantity for items in an order
            
    /// </summary>
            
    /// <param name="inventory"></param>

            void TakeStock(Inventory inventory);
        }

    }


    这个定义了减少库存的操作。
    那么,接下来,我们可以来看看实体类

    using System;
    using System.Collections;
    using PetShop.Helper;
    using PetShop.IDAO;

    namespace PetShop.BLL{
        
    /// <summary>
        
    /// Business entity used to model an order
        
    /// </summary>

        [Serializable]
        
    public class Order{
            
    // These variables are used to demonstrate the rollback characterisitic 
            
    // of distributed transactions and would not form part of a production application
            private const string ACID_USER_ID = "ACID";
            
    private const string ACID_ERROR_MSG = "ACID test exception thrown for distributed transaction!";

            
    private int _orderId;
            
    private DateTime _date;
            
    private string _userId;
            
    private CreditCard _creditCard;
            
    private Address _billingAddress;
            
    private Address _shippingAddress;
            
    private decimal _orderTotal;
            
    private string _courier = "UPS";
            
    private string _locale = "US_en";
            
    private IList _lineItems;
            
    private OrderStatus _status;

            
    public int OrderId{
                
    get return _orderId; }
            }


            
    public DateTime Date{
                
    get return _date; }
                
    set { _date = value; }
            }


            
    public string UserId{
                
    get return _userId; }
                
    set { _userId = value; }
            }


            
    public CreditCard CreditCard{
                
    get return _creditCard; }
                
    set { _creditCard = value; }
            }


            
    public Address BillingAddress{
                
    get return _billingAddress; }
                
    set { _billingAddress = value; }
            }


            
    public Address ShippingAddress{
                
    get return _shippingAddress; }
                
    set { _shippingAddress = value; }
            }


            
    public decimal OrderTotal{
                
    get return _orderTotal; }
                
    set { _orderTotal = value; }
            }


            
    public IList LineItems {
                
    get return _lineItems; }
                
    set 
                    
    int lineNum = 1;
                    
    foreach(CartItem item in value){
                        item.LineNum 
    = lineNum++;
                        item.Order   
    = this;
                    }

                    _lineItems 
    = value;
                }

            }

            
            
    public OrderStatus Status {
                
    get return _status; } 
                
    set {
                    _status 
    = value;
                    _status.Order 
    = this;
                }

            }


            
    public static Order Load(int orderId) {
                
    // Validate input
                if (orderId < 1return null;

                
    // Return the order from the DAL
                return ((IOrderDAO)ObjectFactory.GetInstance("OrderDAO")).GetOrder(orderId);
            }

            
            
    public void Insert(){
                IManagedTransactionContext mtc 
    = new TransHelper();
                mtc.DoCallback( 
    new ContextCallback(InsertInTransaction) ); 
            }


            
    /// <summary>
            
    /// A method to insert a new order into the system
            
    /// The orderId will be generated within the method and should not be supplied
            
    /// As part of the order creation the inventory will be reduced by the quantity ordered
            
    /// </summary>
            
    /// <param name="order">All the information about the order</param>

            private void InsertInTransaction(){
                
                
    // Call the insert method in the DAL to insert the header
                this.Status = new OrderStatus();

                ((IOrderDAO)ObjectFactory.GetInstance(
    "OrderDAO")).Insert(this);
                
                
    foreach(CartItem item in LineItems){
                    item.TakeStock();
                }

            
                
    // As part of the sample application we have created a user 
                
    // you can tested distributed transactions with
                
    // If the order has been created with the user 'Acid', 
                
    // then throw an exception which will rollback the entire transaction
                if (this.UserId == ACID_USER_ID) throw new ApplicationException(ACID_ERROR_MSG);
            }

        }

    }
    我们在这里可以看到对于这种操作,他得通过一个回调函数来显式的控制事务。
    这样我们就可以不用考虑那么多了,只需要考虑操作步骤。
       1.给Order对象的Status赋值
       2.通过对象工厂获取一个OrderDAO的借口,并执行新增Order操作。
         在这个步骤,Order LineItem OrderStatus被执行了插入操作。
       3.我们需要扣除已经销售的库存
          我们遍历LineItems属性,调用对应的扣除库存的操作

    完成了。其实也不难,只是不知道方法而已:)

  • 相关阅读:
    Elasticsearch的RESTful API使用
    Elasticsearch简介与安装
    安装MySQL
    数据处理与文件查找,压缩与解压
    Linux网络设置
    文件与文件夹
    基本命令
    se
    爬虫请求库之requests
    redis五种数据类型
  • 原文地址:https://www.cnblogs.com/wildfish/p/139107.html
Copyright © 2011-2022 走看看