iBatis + SQL Server 项目开发实战小结

几年前跟随项目经理做的一个ERP小项目,自己业余时间整理的开发手册,供参考。

开发环境配置:编程环境为Microsoft Visual Studio 2010,数据库是SQL Server 2008 R2。设计架构Windows Forms+ .NET Remoting + SQL Server,所有程序的代码量(框架,工具,业务逻辑)在5万行以内。

%26#160;

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])

%26#160;

2%26#160; 设计iBatis映射文件

添加Xml映射文件,放置于ErpMappingClass\Model\SqlMap目录中,同时设置它的生成动作(Build Action)是嵌入式资源(Embedded Resource)

打开FMVendor.xml文件,增加内容如下所示,namespace的值为实体类型名称

%26lt;sqlMap namespace=%26quot;FMVendor%26quot; xmlns=%26quot;http://ibatis.apache.org/mapping%26quot; xmlns:xsi=%26quot;http://www.w3.org/2001/XMLSchema-instance%26quot;%26gt;
%26lt;alias%26gt;
%26lt;typeAlias alias=%26quot;FMVendor%26quot; type=%26quot;Erp.Model.FMVendor%26quot;/%26gt;
%26lt;/alias%26gt;

type的值为实体类型定义的完整名称。

在Xml文件中增加不同的节(Element),用于SQL语句对数据的增删查改。

数据操作语句

Xml片段写法

读取

%26lt;select id=%26quot;Select%26quot; parameterClass=%26quot;Hashtable%26quot; resultClass=%26quot;FMVendor%26quot; %26gt;

插入新数据

%26lt;insert id=%26quot;Insert%26quot; parameterClass=%26quot;FMVendor%26quot; resultClass=%26quot;Erp.Model.BaseClass%26quot; %26gt;

更新数据

%26lt;update id=%26quot;Update%26quot; parameterClass=%26quot;FMVendor%26quot; %26gt;

删除数据

%26lt;delete id=%26quot;Delete%26quot; parameterClass=%26quot;Hashtable%26quot;%26gt;

delete $Tablename$ where Id=#Id#

%26lt;/delete%26gt;

注意参数的写法:ColumnName=#ColumnName# 以”#”表示列名对应的参数。

删除数据的Xml代码在BaseClass对应的Xml节中有配置,此处不用写。

%26#160;

3%26#160; 设计实体类型及数据增删查改

实体类型的代码根据Code Smith模板自动生成,同时加上Serializable以支持用于远程调用时对象的可序列化。

3.1%26#160; 根据数据库表的列,生成实体类型定义

[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 %26quot;tbFMVendor%26quot;;
}

3.2 读取一个实体对象(三个重载方法,前两个方法传入不同的参数调用第三个方法)

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

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

public static FMVendor getFMVendorByFilter(Hashtable _htFilter)
{
       FMVendor fmVendor = Select%26lt;FMVendor%26gt;(_htFilter);
       return fmVendor;
}
%26#160;
3.3 读取一个实体集合(两个重载方法,前一个方法传入空值调用第二个方法)
public static IList%26lt;FMVendor%26gt; getAllFormKind()
{
   return getAllFormKindByFilter(null);
}

public static IList%26lt;FMVendor%26gt; getAllFormKindByFilter(Hashtable _htFilter)
{
     IList%26lt;FMVendor%26gt; list = Global.QueryForList%26lt;FMVendor%26gt;(%26quot;FMVendor.Select%26quot;, _htFilter);
     return list;
}
%26#160;
3.4%26#160; 保存数据 保存前做数据验证,验证信息以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 = %26quot;请输入供应商类型代码! %26quot;;
          return result;
    }

    if (string.IsNullOrEmpty(_fmVendor.Name))
    {
           result.Succeed = false;
           result.Message = %26quot;请输入供应商类型名称! %26quot;;
           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 %26amp;%26amp; formkindExist.Id != _fmVendor.Id)
{

        result.Succeed = false;
       result.Message = %26quot;供应商代码重复,请重新输入一个新代码!%26quot;;
       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%26#160; 删除数据

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

FMVendor.xml文件中不需要写SQL删除数据语句,基类型BaseClass中已经有删除方法实现。
%26#160;

4%26#160; 设计远程对象(.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%26lt;NroFMVendor%26gt;(); 
            return nroFMVendor;
          } 
    }
}

修改类型Erp.Model.FlextFactory的RegisterService方法,公开远程服务。

public class FlexFactory
{
     RemotingConfigurationRegisterWellKnownServiceType%26lt;NroFMVendor%26gt;();


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(%26quot;保存成功!%26quot;);
   }
   else
   {
      MessageBox.Show(%26quot;保存失败!\r\n%26quot; + 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;
}

%26#160;

项目总结

1%26#160; iBatis是轻量型ORM,可以将SQL语句返回的结果绑定到对象实体,不过手写SQL语句和增加实体定义文件这两步需要开发人员自己完成。所以需要另外开发Code Smith模板生成代码。

2%26#160; 项目很小,仅限于公司内部员工使用,欠缺很多商业性ERP的特性,欢迎批评指正。







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值