相關連結
最佳Excel匯入實踐(一)
最佳Excel匯入實踐(二)
最佳Excel匯入實踐(三)
最佳Excel匯入實踐(四)
最佳Excel匯入實踐(五)
我們先以銷售訂單為例看一下實際的業務情境:通常在常用的業務系統中都會有單據的儲存操作,如銷售訂單的儲存方法可能如下:OrderService.Save(Order order)。而Excel匯入實際上也是Save功能,只是錄入方式不同而已,一個從普通UI,一個從Excel,所以在本匯入方案中會重用此Save方法。另外,匯入存在很多必要的檢查(如資料類型,值範圍等)。
為了能滿足系統中所有的匯入功能和體現物件導向的設計原則,引入如下匯入規則類:
本例是以表頭表體的業務情境來講解的(如一張訂單中可能有多個商品的分錄),如果只是單一表的結構要比這個簡單。
其中規則包含了常用的檢查以及儲存時要執行的方法等資訊。規則類的建立是根據以下設定檔(當然也可以來源於資料庫):
<ImportConfig id="order">
<!--本設計是討論一種比較複雜的,包含表頭表體的匯入(如一張訂單中可能包含多個商品的分錄)。-->
<!--Excel中的記錄將被映射成的實體物件名(表頭)-->
<HeadClass>BusinessRule.Order</HeadClass>
<!--表頭中對錶體實體引用的屬性名稱。如果不是表頭表體的結構,可以刪除此結點-->
<EntryProperty>OrderEntries</EntryProperty>
<!--Excel中的記錄將被映射成的實體物件名(表體)。如果不是表頭表體的結構,可以刪除此節點-->
<EntryClass>BusinessRule.OrderEntry</EntryClass>
<!--儲存方法所在的類名-->
<MethodClass>BusinessRule.OrderService</MethodClass>
<!--物件建構完成之後調用的儲存方法名-->
<SaveMethod>Save</SaveMethod>
<!--調用儲存方法之前可能會有一些商務邏輯上的檢查,此為檢查的方法名,如果沒有可以刪除此節點-->
<ExValidateMethod>ExValidate</ExValidateMethod>
<!--以下為Excel中各列的資訊配置-->
<!--
IsEntry:是否表體欄位。預設為0,不是表體欄位;
IsPrimaryKey:是否唯一欄位。因一個訂單頭可能對應多個訂單體,即Excel中的多條記錄對應一張訂單。匯入時將根據IsPrimaryKey=1的欄位值來確定哪些行屬於一張訂單。
Property:實體類中對應的屬性名稱。
ColumnName:Excel中對應的列頭名。
Requried:是否必錄項。預設0,不必錄。
DataType:產生引入模板時將根據此產生對應列的有效性驗證。如果是參考型別(DataType=ref),則會根據RefConfig產生下拉式清單及儲存時進行相應的轉換(如將客戶名稱轉換為客戶ID,因為資料庫中存的為ID,Excel中顯示的為名稱)。
RefConfig:參考型別的配置資訊。參考型別一般需要轉換後儲存,故配置項依次為 轉換後的欄位;轉換時尋找的表;轉換時用到的比較欄位;過濾條件。
DefValue:預設值。支援多種預設值:$F{XXX}表示取系統級的變數,當然系統中要首先存在這些變數;$E{a.b}表示取其它對象的相關屬性;$C{XXX}表示預設值為常量;$S{XXX}表示通過SQL取預設值等。
Min:最小值。
Max:最大值。
MaxLen:最大長度。
Comment:產生引入模板時列頭的批註。
-->
<!--表頭欄位-->
<Column IsPrimaryKey="1" Property="OrderNO" ColumnName="訂單編號" Required="1" DataType="string" Comment="編號只能由字母或數字組成。" MaxLen="40"></Column>
<Column Property="OrderDate" ColumnName="訂單日期" Required="1" DataType="date" DefValue="$F{SysDate}" Comment="日期格式為YYYY-MM-DD,如果不錄入則取系統當前日期。"></Column>
<Column Property="CustomerID" ColumnName="客戶名稱" Required="1" DataType="ref" RefConfig="CustomerID;t_Customer;CustomerName;IsUsed=1"></Column>
<!--表體欄位-->
<Column IsEntry="1" Property="InvID" ColumnName="商品名稱" Required="1" DataType="ref" DefValue="InvID;t_Inventory;InvName;"></Column>
<Column IsEntry="1" Property="Qty" ColumnName="數量" Required="1" DataType="decimal" ></Column>
<Column IsEntry="1" Property="Price" ColumnName="單價" Required="1" DataType="decimal" DefValue="$E{InvID.StandardPrice}"></Column>
<Column IsEntry="1" Property="Discount" ColumnName="折扣率(%)" DataType="decimal" Min="0" Max="100" DefValue="$C{0}" Comment="請輸入0-100之前的數字。"></Column>
<!--制單人不用在匯入模板中顯示,但資料庫中要求有值,所以沒有設定ColumnName屬性,只設定了預設值-->
<Column Property="CreateUser" DefValue="$F{UserNO}" ></Column>
</ImportConfig>
各節點的說明已經在注釋中做了詳細的說明。注意,為了代碼的可讀性更好,將其中的RefConfig節點轉換成了對象中的RefField,RefTable,RefConvertField和RefFilter屬性。匯入時執行轉換時將執行類似如下SQL語句:
SELECT top 1 RefField FROM RefTable WHERE RefConvertField='XXX' AND RefFilter
下一篇我們將講Excel匯入模板的產生。