zoukankan      html  css  js  c++  java
  • 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映射文件,放置于ErpMappingClassModelSqlMap目录中,同时设置它的生成动作(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("保存失败!
    " + 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的特性,欢迎批评指正。

  • 相关阅读:
    navicat 连接 mysql 出现Client does not support authentication protocol requested by server解决方案
    oracle的concat、convert、listagg函数(字符串拼接和类型转换)
    oracle的decode、sign、nvl,case...then函数
    where、having区别
    Oracle的rollup、cube、grouping sets函数
    IP地址,子网掩码,网段表示法,默认网关,DNS服务器详解,DNS域名设计
    springmvc 参数解析绑定原理
    eclipse运行mapreduce的wordcount
    linux命令帮助 man bash
    shell学习笔记3-后台执行命令
  • 原文地址:https://www.cnblogs.com/JamesLi2015/p/4688068.html
Copyright © 2011-2022 走看看