iBatis + SQL Server 項目開發實戰小結


幾年前跟隨項目經理做的一個ERP小項目,自己業余時間整理的開發手冊,供參考。

開發環境配置:編程環境為Microsoft Visual Studio 2010,數據庫是SQL Server 2008 R2。設計架構Windows Forms+ .NET Remoting + SQL Server,所有程序的代碼量(框架,工具,業務邏輯)在5萬行以內。

 

1 SQL Server 數據庫表設計

設計供應商表Vendor, tb是通用前綴標識符號。FM是資金管理Finance Management。

CREATE TABLE [dbo].[tbFMVendor](
[Id] [bigint] IDENTITY(1,1) NOT NULL,
[Code] [nvarchar](50) NULL,
[Name] [nvarchar](50) NULL,
[Description] [nvarchar](50) NULL,
CONSTRAINT [PK_tbVendor] PRIMARY KEY CLUSTERED 
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]

) ON [PRIMARY]

clip_image008

iBatis框架要求每個表要以Id作為主鍵,類型為(C#:Int64, Sql:bigint)是個自增型。因為Id是唯一的,所以從表不需要設計多主鍵與主表關聯。

如果是從表(明細表),則需要添加對主表的Id列的外鍵引用。參考下面的腳本例子。

ALTER TABLE [dbo].[tbCustomerDiscBankAcct] ADD CONSTRAINT [FK_tbCustomerDiscBankAcct_tbCustomer] FOREIGN KEY ([IdCustomer]) REFERENCES [dbo].[tbCustomer] ([Id])

 

2  設計iBatis映射文件

添加Xml映射文件,放置於ErpMappingClass\Model\SqlMap目錄中,同時設置它的生成動作(Build Action)是嵌入式資源(Embedded Resource)

打開FMVendor.xml文件,增加內容如下所示,namespace的值為實體類型名稱

<sqlMap namespace="FMVendor" xmlns="http://ibatis.apache.org/mapping" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<alias>
<typeAlias alias="FMVendor" type="Erp.Model.FMVendor"/>
</alias>

type的值為實體類型定義的完整名稱。

在Xml文件中增加不同的節(Element),用於SQL語句對數據的增刪查改。

數據操作語句

Xml片段寫法

讀取

<select id="Select" parameterClass="Hashtable" resultClass="FMVendor" >

插入新數據

<insert id="Insert" parameterClass="FMVendor" resultClass="Erp.Model.BaseClass" >

更新數據

<update id="Update" parameterClass="FMVendor" >

刪除數據

<delete id="Delete" parameterClass="Hashtable">

delete $Tablename$ where Id=#Id#

</delete>

注意參數的寫法:ColumnName=#ColumnName# 以”#”表示列名對應的參數。

刪除數據的Xml代碼在BaseClass對應的Xml節中有配置,此處不用寫。

 

3  設計實體類型及數據增刪查改

實體類型的代碼根據Code Smith模板自動生成,同時加上Serializable以支持用於遠程調用時對象的可序列化。

3.1  根據數據庫表的列,生成實體類型定義

[Serializable]
public class FMVendor: BaseClass
{

public string Code { get; set; }
public string Name { get; set; }
public string Description { get; set; }

}

重寫BaseClass的tm_getTableName方法,返回實體映射的數據庫表名稱。

protected override string tm_getTableName()
{
      return "tbFMVendor";
}

3.2 讀取一個實體對象(三個重載方法,前兩個方法傳入不同的參數調用第三個方法)

public static FMVendor getFMVendorById(Int64 _Id)
{
     Hashtable htFilter = new Hashtable();
     htFilter.Add("Id", _Id);
     return getFMVendorByFilter(htFilter);
}

public static FMVendor getFMVendorByCode(String _Code)
{
      Hashtable htFilter = new Hashtable();
      htFilter.Add("Code", _Code);
      return getFMVendorByFilter(htFilter);
}

public static FMVendor getFMVendorByFilter(Hashtable _htFilter)
{
       FMVendor fmVendor = Select<FMVendor>(_htFilter);
       return fmVendor;
}
 
3.3 讀取一個實體集合(兩個重載方法,前一個方法傳入空值調用第二個方法)
public static IList<FMVendor> getAllFormKind()
{
   return getAllFormKindByFilter(null);
}

public static IList<FMVendor> getAllFormKindByFilter(Hashtable _htFilter)
{
     IList<FMVendor> list = Global.QueryForList<FMVendor>("FMVendor.Select", _htFilter);
     return list;
}
 
3.4  保存數據 保存前做數據驗證,驗證信息以DataResult對象傳回
public static DataResult saveFMVendor(ref FMVendor _fmVendor, String _userCode)
{

    DataResult result = new DataResult(false);
    if (string.IsNullOrEmpty(_fmVendor.Code))
   {

          result.Succeed = false;
          result.Message = "請輸入供應商類型代碼! ";
          return result;
    }

    if (string.IsNullOrEmpty(_fmVendor.Name))
    {
           result.Succeed = false;
           result.Message = "請輸入供應商類型名稱! ";
           return result;
    }

//數據校效
User user = User.getUserByCode(_userCode);
FMVendor fmVendor = getFMVendorById(_fmVendor.Id);
if (fmVendor == null)
{

      _fmVendor.Id = 0;
}

FMVendor formkindExist = getFMVendorByCode(_fmVendor.Code);
if (formkindExist != null && formkindExist.Id != _fmVendor.Id)
{

        result.Succeed = false;
       result.Message = "供應商代碼重復,請重新輸入一個新代碼!";
       return result;
}

try
{

   Global.BeginTransaction();
   _fmVendor.Save();
   Global.CommitTransaction();
   result.Succeed = true;
   return result;
}
catch (Exception ex)
{
   Global.RollBackTransaction();
   result.Succeed = false;
   result.Message = ex.Message;
   return result;
}
}

3.5  刪除數據

public static String deleteFMVendor(Int64 vendorId)
{
   DataResult result = new DataResult();
   try
   {
        FMVendor fmVendor = GsctErp.Model.FMVendor.getFMVendorById(vendorId);
        if (fmVendor != null)
        {
                  fmVendor.Delete();
         }
         return "刪除成功 ! ";
    }
    catch (Exception ex)
    {
       return "刪除失敗 ! " + ex.Message;
    }
}

FMVendor.xml文件中不需要寫SQL刪除數據語句,基類型BaseClass中已經有刪除方法實現。
 

4  設計遠程對象(.NET Remoting)

遠程對象需要公開相應的數據訪問方法給客戶端界面調用。

public class NroFMVendor: BaseClass
{

}

遠程對象命名規則在原有的對象名稱前加Nro前綴,並繼承於BaseClass,它的方法是對實體對象的數據訪問的封裝,每個方法的第一行是用戶驗證代碼。

public FMVendor getFMVendorById(Int64 _Id)
{
    User user = ValidateIdentity();
    return FMVendor.getFMVendorById(_Id);
}

public FMVendor getFMVendorByCode(string Code)
{
       User user = ValidateIdentity();
       return FMVendor.getFMVendorByCode(Code);
}

public DataResult saveFMVendor(ref FMVendor vendor, String _userCode)
{
       User user = ValidateIdentity();
       return FMVendor.saveFMVendor(ref vendor, _userCode);
}

修改類型Erp.Model. FlexFactory,在該類型中增加私有靜態變量

增加公共屬性,以用於客戶端的界面訪問,需要增加的代碼如下所示

public class FlexFactory
{

    private static NroFMVendor nroFMVendor;
    public static NroFMVendor myNroFMVendor
    { 

      get {
           if (nroFMVendor == null) 
               nroFMVendor = ActivatorGetObject<NroFMVendor>(); 
            return nroFMVendor;
          } 
    }
}

修改類型Erp.Model.FlextFactory的RegisterService方法,公開遠程服務。

public class FlexFactory
{
     RemotingConfigurationRegisterWellKnownServiceType<NroFMVendor>();


5 界面開發

在項目中增加窗體FrmDtlVendor.cs,繼承於FrmDtlBase。

public partial class FrmDtlVendor : FrmDtlBase
{
    public FrmDtlVendor()
{
    InitializeComponent();
}

private FMVendor _vendor;
public void setVendor(FMVendor vendor)
{
    _vendor = vendor;
}

它是對單筆數據進行操作,界面如下所示

image

ERP系統中預定義的窗體基類型列表如下,可根據業務需要繼承。

類型名稱

用途

FrmLstBase

以列表形式呈現數據

clip_image014

FrmDtlBase

單筆數據的編輯(增刪查改)操作

clip_image016

FrmSchClass

數據搜索窗體

clip_image020

FrmRptFlt

報表參數值選擇

clip_image022

FrmScnClass

查詢方案

clip_image024

FrmImpBase

數據導入

clip_image026

回到FmVendorDtl窗體中,在OnLoad方法加載數據。

protected override void OnLoad(EventArgs e)
{

   this.Text = SysParam.ClientSysTitle;
   setRight();
   FMVendor fmVendor = _vendor == null ? null : GsctFactory.myNroFMVendor.getFMVendorById(_vendor.Id);
   if (fmVendor == null)
      clearForm();
  else
     showVendor(fmVendor);
   bindProfile();
   this.CenterToParent();
}

有二種方法啟動這個窗體,當從List列表進入時,根據傳入的對象值加載數據,並綁定到界面控件中,同時設置權限,對控件進行隱藏或是禁用處理。

增加數據保存代碼,示例方法如下所示

private void tsbSave_Click(object sender, EventArgs e)
{

   DataResult result = saveVendor();
   if (result.Succeed)
   {

       showVendor(_vendor);
       MessageBox.Show("保存成功!");
   }
   else
   {
      MessageBox.Show("保存失敗!\r\n" + result.Message);
    }
}

saveVendor方法中的對象保存代碼是調用遠程對象的方法,片段如下

try
{

    vendor.Code = txtCode.Text.Trim();
    vendor.Name = txtName.Text;
    result = GsctFactory.myNroFMVendor.saveFMVendor(ref vendor, User.currUser.Code);
    if (!result.Succeed) 
        throw new Exception(result.Message);
}
catch (Exception ex)
{
     result.Message = ex.Message;
     return result;
}

 

項目總結

1  iBatis是輕量型ORM,可以將SQL語句返回的結果綁定到對象實體,不過手寫SQL語句和增加實體定義文件這兩步需要開發人員自己完成。所以需要另外開發Code Smith模板生成代碼。

2  項目很小,僅限於公司內部員工使用,欠缺很多商業性ERP的特性,歡迎批評指正。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM