Git.Framework 框架随手记--存储过程简化

  在很多的ORM中对存储过程操作都是一个棘手的地方,因为存储过程是一段预编译的代码,其中可以包含很多处理过程。在Git.Framework中也同样存在这样的问题,目前没有能力解决这个问题。但是对于存储过程的一些外围操作目前还是可以支持的。

    上一篇文章简单回顾地址,可能对了解本文有益: Git.Framework 框架随手记--SQL配置文件的使用

  一. 结构简单说明

    在前面操作基本SQL的时候我们已经知道使用对象模型映射其相关的表,一些基本的操作我们都能够实现完成。在很大的程度上完成了抽象工作,在实现存储过程的时候我们同意遵循抽象的原则。每一个存储过程我们都映射成为一个实体类,而这个存储过程的实体类也必须继承自BaseEntity。先简单看看如下一个存储过程的映射类。

/*******************************************************************************
* Copyright (C) Git Corporation. All rights reserved.
*
* Author: 代码工具自动生成
* Create Date: 2014/03/02 09:57:38
* Blog: http://www.cnblogs.com/qingyuan/
* Description: Git.Framework
*
* Revision History:
* Date Author Description
* 2014/03/02 09:57:38
*********************************************************************************/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using Git.Framework.ORM;

namespace Git.Storage.Entity.InStorage
{
[TableAttribute(DbName = "JooShowGit", Name = "Proc_AuditeInStorage", IsInternal = false,MapType=MapType.Proc)]
public partial class Proc_AuditeInStorageEntity:BaseEntity
{
public Proc_AuditeInStorageEntity()
{
}

[DataMapping(ColumnName = "OrderNum", DbType = DbType.String, Length = 20,ColumnType=ColumnType.InPut)]
public string OrderNum { get; set; }

[DataMapping(ColumnName = "Status", DbType = DbType.Int32, Length = 4000,ColumnType=ColumnType.InPut)]
public Int32 Status { get; set; }

[DataMapping(ColumnName = "AuditUser", DbType = DbType.String, Length = 20,ColumnType=ColumnType.InPut)]
public string AuditUser { get; set; }

[DataMapping(ColumnName = "Reason", DbType = DbType.String, Length = 400,ColumnType=ColumnType.InPut)]
public string Reason { get; set; }

[DataMapping(ColumnName = "OperateType", DbType = DbType.Int32, Length = 4000,ColumnType=ColumnType.InPut)]
public Int32 OperateType { get; set; }

[DataMapping(ColumnName = "EquipmentNum", DbType = DbType.String, Length = 20,ColumnType=ColumnType.InPut)]
public string EquipmentNum { get; set; }

[DataMapping(ColumnName = "EquipmentCode", DbType = DbType.String, Length = 20,ColumnType=ColumnType.InPut)]
public string EquipmentCode { get; set; }

[DataMapping(ColumnName = "Remark", DbType = DbType.String, Length = 400,ColumnType=ColumnType.InPut)]
public string Remark { get; set; }

[DataMapping(ColumnName = "ReturnValue", DbType = DbType.String, Length = 50,ColumnType=ColumnType.InOutPut)]
public string ReturnValue { get; set; }

}
}

存储过程映射类

    上面这个实体类第一眼看和之前的没有什么区别,如果观察仔细这里还是有小小的区别的,在某些标识特性上存在着差异。

[TableAttribute(DbName = "JooShowGit", Name = "Proc_AuditeInStorage",  IsInternal = false,MapType=MapType.Proc)]

    在前面TableAttribute是指定的表的映射,这里同样适用于存储过程的的标识。但是这里多了一个标识符,MapType=MapType.Proc.
指定映射为存储过程,默认情况是Table
和View的映射。前面没有提到View,View在结构上和Table没有太大的差异,所以直接将View当做Table使用即可。

[DataMapping(ColumnName = "OrderNum", DbType = DbType.String, Length = 20,ColumnType=ColumnType.InPut)]
public string OrderNum { get; set; }

    这是一个字段映射的过程,和之前也没有什么区别,但是这里似乎有很多属性没有了,因为没有任何意义,所以不填写也没关系,即使填写了不起任何作用。但是这里需要制定一个ColumnType属性,上一篇讲到了参数类型有几种类型,这里就是指定其类型的。上面一段代码则是指定这个字段为输入参数。

[DataMapping(ColumnName = "ReturnValue", DbType = DbType.String, Length = 50,ColumnType=ColumnType.InOutPut)]
public string ReturnValue { get; set; }

    这段代码这是指定了一个属性字段为输出参数类型,在调用存储过程执行成功之后,存储过程返回的值会自动填充到这个属性中,不需要我们做任何其他的处理,还是比较方便。

public enum ColumnType
{
InPut = 1,
OutPut = 2,
InOutPut = 3,
Return = 4,
Common = 10,
}

字段类型枚举值的定义

    这个枚举值就是ColumnType的详细定义,总共有有5中定义,但是其中用到的最多也就是4种,都是我们比较熟悉的。

  二. 存储过程接口的定义

    在前面已经说过了,这个框架都遵循一定程度的抽象,无论是对表,视图,存储过程,还是函数我们都遵循一定规则的抽象。存储过程是一段已编译的代码,而由于存储过程的本身复杂性,在很多ORM框架中都对存储过程支持的不是那么彻底。该框架也是如此,但是在某种程度上还是可以完成一般性工作的。对于存储过程的支持,我们这里采用另外的一个接口形式。

public interface IDbProcHelper<T> : IDisposable where T : Git.Framework.ORM.BaseEntity
{
V ExceuteEntity<V>(T entity) where V : class, new();
List<V> ExceuteEntityList<V>(T entity) where V : class, new();
int ExecuteNonQuery(T entity);
V ExecuteScalar<V>(T entity);
object ExecuteScalar(T entity);
}

存储过程抽象接口

    上面这段代码就是对存储过程操作的公共接口,其中只有5个方法,相比IDbHelper<T>要简单多了,而且其中这五个方法的方法名和ADO.NET中定义的一样,这样是为了更好简单的从ADO.NET过渡到这个上面来。

public partial interface IProc_AuditeInStorage : IDbProcHelper<Proc_AuditeInStorageEntity>
{
}

    这里是一个存储过程对应的接口,该存储过程必须继承自抽象接口IDbProcHelper<T>,在上面提到过了,继承这个抽象接口意味着具有其所有的方法,同时也指明了这个接口具体操作哪个存储过程。其接口实现过程如下:

public partial class Proc_AuditeInStorageDataAccess : DbProcHelper<Proc_AuditeInStorageEntity>, IProc_AuditeInStorage
{
public Proc_AuditeInStorageDataAccess()
{
}

}

存储过程实现类

    上面这段代码是存储过程接口的实现,从结构上和之前说的结构没有任何区别,执行继承的类稍微做了一些修改。而且必须遵循这种结构,这是保证运行的基础。有人会问是不是可以使用配置做的更加灵活一点,答案是的,但是我个人遵循的观点是"约束大于配置"。

  三. 如何使用

    存储过程的使用也非常简单,和之前的操作没有太大的区别。在使用之前我们先建好存储过程。

    (1) 新建一个存储过程

----------------------------------------------------------------------------------------------------------------
--*******************************************入库审核存储过程***************************************************
--**************************************************************************************************************
-- 1000 审核成功
-- 1001 入库单不存在
-- 1002 入库单已经审核
----------------------------------------------------------------------------------------------------------------
IF EXISTS(SELECT * FROM SYSOBJECTS WHERE NAME = ‘Proc_AuditeInStorage‘)
DROP PROCEDURE Proc_AuditeInStorage
GO
CREATE PROCEDURE Proc_AuditeInStorage
(
@OrderNum VARCHAR(20),--入库单号
@Status int,--审核状态
@AuditUser nvarchar(20),--审核人编号
@Reason nvarchar(400), --审核成功或者失败的原因
@OperateType int, --操作方式 1 电脑 2 PDA
@EquipmentNum varchar(20), --设备编号[所使用的设备编号]
@EquipmentCode varchar(20), --设备条码[如果没有就直接设备编号]
@Remark nvarchar(400),--入库单描述
@ReturnValue varchar(50) OUTPUT
)
AS
BEGIN
--判断入库单是否存在
IF NOT EXISTS ( SELECT COUNT(*) FROM InStorage WHERE OrderNum=@OrderNum AND IsDelete=0)
BEGIN
SET @ReturnValue=‘1001‘
RETURN
END

--判断入库单是否已经被审核 查询入库单等待审核是否存在
IF NOT EXISTS ( SELECT COUNT(*) FROM InStorage WHERE OrderNum=@OrderNum AND Status=1 AND IsDelete=0)
BEGIN
SET @ReturnValue=‘1002‘
RETURN
END

DECLARE @ProductName nvarchar(100)
DECLARE @BarCode varchar(50)
DECLARE @ProductNum varchar(50)
DECLARE @BatchNum nvarchar(20)
DECLARE @Num int
DECLARE @LocalNum varchar(20)
DECLARE @StorageNum varchar(20)

DECLARE MyCursor CURSOR FOR SELECT [ProductName],[BarCode],[ProductNum],[BatchNum],[Num],[LocalNum],[StorageNum] FROM InStorDetail WHERE OrderNum= @OrderNum
OPEN MyCursor FETCH NEXT FROM MyCursor INTO @ProductName, @BarCode,@ProductNum,@BatchNum,@Num,@LocalNum,@StorageNum
WHILE @@FETCH_STATUS = 0
BEGIN

--盘点库存是否存在
IF (SELECT COUNT(*) FROM LocalProduct WHERE ProductNum=@ProductNum AND StorageNum=@StorageNum AND LocalNum=@LocalNum)>0
BEGIN
--如果存在则修改相应的库存数量
UPDATE LocalProduct SET Num=Num+@Num WHERE ProductNum=@ProductNum AND StorageNum=@StorageNum AND LocalNum=@LocalNum
END
ELSE
BEGIN
--如果不存在则添加

--获得SN流水号
DECLARE @SN varchar(50)
EXEC Proc_SwiftNum ‘‘,‘LocalProduct‘,@SN OUTPUT

DECLARE @StorageName nvarchar(50)
DECLARE @LocalName nvarchar(50)
DECLARE @LocalType int
DECLARE @UserName nvarchar(50)

SELECT TOP 1 @StorageName=StorageName FROM Storage WHERE StorageNum=@StorageNum
SELECT TOP 1 @LocalName=LocalName,@LocalType=LocalType FROM Location WHERE LocalNum=@LocalNum AND StorageNum=@StorageNum
SELECT TOP 1 @UserName=UserName FROM Admin WHERE UserCode=@AuditUser

INSERT INTO [dbo].[LocalProduct]([Sn],[StorageNum],[StorageName],[LocalNum],[LocalName],[LocalType],[ProductNum],[BarCode],[ProductName],[Num],[CreateTime],[CreateUser],[CreateName],[Remark])
VALUES(@SN,@StorageNum,@StorageName,@LocalNum,@LocalName,@LocalType,@ProductNum,@BarCode,@ProductName,@Num,GETDATE(),@AuditUser,@UserName,‘‘)
END

--入库台账记录生成
INSERT INTO [dbo].[InventoryBook]([ProductNum],[BarCode],[ProductName],[Num],[Type],[ContactOrder],[FromLocalNum],[ToLocalNum],[StoreNum],[CreateTime],[CreateUser])
VALUES(@ProductNum,@BarCode,@ProductName,@Num,1,@OrderNum,‘‘,@LocalNum,@StorageNum,GETDATE(),@AuditUser)

--进行下一个游标循环
FETCH NEXT FROM MyCursor INTO @ProductName, @BarCode,@ProductNum,@BatchNum,@Num,@LocalNum,@StorageNum
END

CLOSE MyCursor
DEALLOCATE MyCursor--释放游标

--修改订单状态
UPDATE InStorage SET Status=@Status,AuditUser=@AuditUser,AuditeTime=GETDATE(),Reason=@Reason,OperateType=@OperateType,
EquipmentNum=@EquipmentNum,EquipmentCode=@EquipmentCode,Remark=@Remark
WHERE OrderNum=@OrderNum

SET @ReturnValue=‘1000‘
END
GO

新建一个存储过程

     上面的代码新建了一个存储过程,这段代码是我们开发的一个条码仓库系统中的一个存储过程,相对比较简单其中有多个输入参数,同时也有一个输出参数。

    (2) 使用工具映射生成实体类

/*******************************************************************************
* Copyright (C) Git Corporation. All rights reserved.
*
* Author: 代码工具自动生成
* Create Date: 2014/03/02 09:57:38
* Blog: http://www.cnblogs.com/qingyuan/
* Description: Git.Framework
*
* Revision History:
* Date Author Description
* 2014/03/02 09:57:38
*********************************************************************************/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using Git.Framework.ORM;

namespace Git.Storage.Entity.InStorage
{
[TableAttribute(DbName = "JooShowGit", Name = "Proc_AuditeInStorage", IsInternal = false,MapType=MapType.Proc)]
public partial class Proc_AuditeInStorageEntity:BaseEntity
{
public Proc_AuditeInStorageEntity()
{
}

[DataMapping(ColumnName = "OrderNum", DbType = DbType.String, Length = 20,ColumnType=ColumnType.InPut)]
public string OrderNum { get; set; }

[DataMapping(ColumnName = "Status", DbType = DbType.Int32, Length = 4000,ColumnType=ColumnType.InPut)]
public Int32 Status { get; set; }

[DataMapping(ColumnName = "AuditUser", DbType = DbType.String, Length = 20,ColumnType=ColumnType.InPut)]
public string AuditUser { get; set; }

[DataMapping(ColumnName = "Reason", DbType = DbType.String, Length = 400,ColumnType=ColumnType.InPut)]
public string Reason { get; set; }

[DataMapping(ColumnName = "OperateType", DbType = DbType.Int32, Length = 4000,ColumnType=ColumnType.InPut)]
public Int32 OperateType { get; set; }

[DataMapping(ColumnName = "EquipmentNum", DbType = DbType.String, Length = 20,ColumnType=ColumnType.InPut)]
public string EquipmentNum { get; set; }

[DataMapping(ColumnName = "EquipmentCode", DbType = DbType.String, Length = 20,ColumnType=ColumnType.InPut)]
public string EquipmentCode { get; set; }

[DataMapping(ColumnName = "Remark", DbType = DbType.String, Length = 400,ColumnType=ColumnType.InPut)]
public string Remark { get; set; }

[DataMapping(ColumnName = "ReturnValue", DbType = DbType.String, Length = 50,ColumnType=ColumnType.InOutPut)]
public string ReturnValue { get; set; }

}
}

Proc_AuditeInStorageEntity
存储过程实体类

      上面已经讲到了这段代码的含义,这里不在累述。

    (3)做好接口的继承以及实现

      上面已经说到了接口继承和和实现,这里不在贴代码,因为结构是一样的。

    (4)调用存储过程返回值

Proc_AuditeInStorageEntity auditeEntity = new Proc_AuditeInStorageEntity();
auditeEntity.OrderNum = entity.OrderNum;
auditeEntity.Status = entity.Status;
auditeEntity.AuditUser = entity.AuditUser;
auditeEntity.Reason = entity.Reason;
auditeEntity.OperateType = entity.OperateType;
auditeEntity.EquipmentNum = entity.EquipmentNum;
auditeEntity.EquipmentCode = entity.EquipmentCode;
auditeEntity.Remark = entity.Remark;
int line = this.Proc_AuditeInStorage.ExecuteNonQuery(auditeEntity);
return auditeEntity.ReturnValue;

调用存储过程

      上面这段就是调用存储过程并且返回输出参数的案例,我们将存储过程的参数映射为一个对象了,在调用存储过程的时候直接将对象传入自动处理输入输出参数。可以从上面的代码看到,输出参数会自动封装到传入的类中指定的属性中去。

    使用案例下载链接:http://pan.baidu.com/s/1sj6S4yT

    因为这个系列的文章所涉及的东西全是公司项目的的部分截取,非主观臆断的编码和设计,是诸多项目的实战所积累,所以不便完全透漏,望请见谅。如果您想有跟深层次的了解可以加群号: 88718955 

时间: 2024-08-05 19:07:09

Git.Framework 框架随手记--存储过程简化的相关文章

Git.Framework 框架随手记--ORM项目工程

前面已经简单介绍过了该框架(不一定是框架),本文开始重点记录其使用过程.可能记录的内容不是太详尽,框架也可能非常烂,但是里面的代码句句是实战项目所得.本文非教唆之类的文章,也非批判之类的文章,更不是炫技之类的文章,只是工作的记录和总结,希望能够给大家一些启迪,忘诸位勿喷! 一. 组建项目需要的几个部分 .NET中最为经典的三层结构,众所周知,无人不晓. 在Git.Framework框架中我们也遵循最基本的这种结构,ORM部分我们划分为如下: 数据实体层,数据访问接口层,数据访问层,[层序主入口加

Git.Framework 框架随手记--ORM条件组合

在上一篇<Git.Framework 框架随手记--ORM新增操作>中简单记录了如何对数据进行删除和修改,其用法都非常简单,在文章中提到了Where()方法,本文将详述Where() 等条件函数. 一. SQL 条件分析 对于SQL每个人应该都很熟悉,这是基础的基础,如果没有使用过SQL的本文可以直接忽略了.先简单看看一个SQL语句,我们根据SQL语句的规则理解Where()方法 SELECT [ID],[UserName],[PassWord],[UserCode],[RealName],[

Git.Framework 框架随手记--SQL配置文件的使用

前面几篇文章讲到了如何使用框架进行简单结构的增删改查操作,由于个人能力有限在对于复杂的SQL操作面前也是无能为力,只能自己动手来写SQL语句.在Git.Framework中提供了一个公共的接口来直接操作SQL语句. 一. SQL配置文件的结构简介 在这个框架中提供了单独的配置文件用于来管理SQL语句,当然也可以不用配置文件.使用SQL配置文件系统在启动的时候会直接将SQL配置文件转化为Command对象缓存,而不用后期再去创建,这是一个比较不错的优势.下面先看看SQL配置文件的结构 <dataO

Git.Framework 框架随手记--ORM新增操作

本篇主要记录具体如何新增数据,废话不多说,开始进入正文. 一. 生成工程结构 上一篇已经说到了如何生成工程结构,这里在累述一次. 1. 新建项目总体结构 使用VS新建项目结构,分层结构可以随意.我们使用的结构如下: 2. 引入配置文件相关 Configs文件夹中的配置文件,其目录结构如下图: 以上几个文件为必须的,除了最下面的画红线的为自定义可以修改,具体配置项内容可以参考前面几篇文章.然后再web.config定义如下配置: <appSettings> <add key="D

Git.Framework 框架随手记--ORM查询返回实体对象

使用ORM有一个优势,可以通过某种机制将数据库中的数据转化为自己想要的对象形式数据.本章记录一下如何使用Git.Framework返回实体对象 一. Git.Framework 中提供的方法 在Git.Framework中有七个方法可以返回实体对象,先简答的看看这里的方法描述 (1) T GetSingle(int id); (2) T GetSingle(object value); (3) T GetSingle(T entity); (4) V GetSingle<V>(T entity

Git.Framework 框架随手记--ORM查询数据集合 一

本文记录Git.Framework之ORM中最为浓墨重彩的一篇,查询集合.根据自己做的项目统计这个是使用频率最高的一个. 一. 查询集合方法简介 (1)List<T> GetList(); (2)List<T> GetList(bool isOpenTrans); (3)List<T> GetList(T entity); (4)List<V> GetList<V>(T entity) where V : class, new(); (5)Lis

Git.Framework 框架随手记--IIS7运行序列化问题

客户反馈系统又登录不了,这是最近几次连续出现相同的问题,从日志反应情况来看: 日志级别:[info] 日志位置:Git.Framework.Resource.ResourceManager 日志时间:2014/12/3 9:08:30 日志内容:反序列化异常:Unable to generate a temporary class (result=1). error CS1567: Error generating Win32 resource: 另一个程序正在使用此文件,进程无法访问. 日志级

DRF (Django REST framework) 框架介绍

Web应用模式 在开发Web应用中,有两种应用模式: 前后端不分离 前后端分离 1 前后端不分离 在前后端不分离的应用模式中,前端页面看到的效果都是由后端控制,由后端渲染页面或重定向,也就是后端需要控制前端的展示,前端与后端的耦合度很高. 这种应用模式比较适合纯网页应用,但是当后端对接App时,App可能并不需要后端返回一个HTML网页,而仅仅是数据本身,所以后端原本返回网页的接口不再适用于前端App应用,为了对接App后端还需再开发一套接口. 2 前后端分离 在前后端分离的应用模式中,后端仅返

Django REST framework框架详解

Django REST framework 简介 在序列化与反序列化时,虽然操作的数据不尽相同,但是执行的过程却是相似的,也就是说这部分代码是可以复用简化编写的. 在开发REST API的视图中,虽然每个视图具体操作的数据不同,但增.删.改.查的实现流程基本套路化,所以这部分代码也是可以复用简化编写的: 增:校验请求数据 -> 执行反序列化过程 -> 保存数据库 -> 将保存的对象序列化并返回 删:判断要删除的数据是否存在 -> 执行数据库删除 改:判断要修改的数据是否存在 -&g