bp(net core)+easyui+efcore實現倉儲管理系統——入庫管理之三存儲過程(三十九)

来源:https://www.cnblogs.com/chillsrc/archive/2020/03/07/12434052.html
-Advertisement-
Play Games

在上一篇文章Abp(net core)+easyui+efcore實現倉儲管理系統——入庫管理之二(三十八) 中我們創建了入庫單的一些有關DTO類與分頁類。由於入庫單我使用了到了資料庫的存儲過程,那麼本篇文章中我們來學習一下如何在ABP中調用存儲過程。 我們都知道,倉儲管理系統中的單號最基本... ...


abp(net core)+easyui+efcore實現倉儲管理系統目錄

abp(net core)+easyui+efcore實現倉儲管理系統——ABP總體介紹(一) abp(net core)+easyui+efcore實現倉儲管理系統——解決方案介紹(二) abp(net core)+easyui+efcore實現倉儲管理系統——領域層創建實體(三)  abp(net core)+easyui+efcore實現倉儲管理系統——定義倉儲並實現 (四) abp(net core)+easyui+efcore實現倉儲管理系統——創建應用服務(五) abp(net core)+easyui+efcore實現倉儲管理系統——展現層實現增刪改查之控制器(六) abp(net core)+easyui+efcore實現倉儲管理系統——展現層實現增刪改查之列表視圖(七) abp(net core)+easyui+efcore實現倉儲管理系統——展現層實現增刪改查之增刪改視圖(八) abp(net core)+easyui+efcore實現倉儲管理系統——展現層實現增刪改查之菜單與測試(九) abp(net core)+easyui+efcore實現倉儲管理系統——多語言(十) abp(net core)+easyui+efcore實現倉儲管理系統——使用 WEBAPI實現CURD (十一) abp(net core)+easyui+efcore實現倉儲管理系統——菜單-上 (十六)

abp(net core)+easyui+efcore實現倉儲管理系統——EasyUI前端頁面框架 (十八)

abp(net core)+easyui+efcore實現倉儲管理系統——EasyUI之貨物管理一 (十九) abp(net core)+easyui+efcore實現倉儲管理系統——ABP WebAPI與EasyUI結合增刪改查之一(二十七) abp(net core)+easyui+efcore實現倉儲管理系統——ABP WebAPI與EasyUI結合增刪改查之三(二十九)

abp(net core)+easyui+efcore實現倉儲管理系統——ABP WebAPI與EasyUI結合增刪改查之八(三十四)

abp(net core)+easyui+efcore實現倉儲管理系統——ABP WebAPI與EasyUI結合增刪改查之十(三十六) abp(net core)+easyui+efcore實現倉儲管理系統——入庫管理之一(三十七) abp(net core)+easyui+efcore實現倉儲管理系統——入庫管理之二(三十八)    

   在上一篇文章Abp(net core)+easyui+efcore實現倉儲管理系統——入庫管理之二(三十八) 中我們創建了入庫單的一些有關DTO與分頁類由於入庫單我使用了到了資料庫的存儲過程,那麼本篇文章中我們來學習一下如何在ABP中調用存儲過程。

   我們都知道,倉儲管理系統中的單號最基本的要求就是唯一,這個條件必須滿足。或者說對於任何有單號的系統來說單號必須唯一,這是硬性要求。

   先來講講對於單號命名的幾種規則:

1、不重覆。

  這點我相信大家都懂,單號的唯一性不用解釋。

2、安全性。

  你的單號編號儘量不要透露你公司的真實運營信息,比如你的單號就是流水號的話,那麼別人就可以從單號推測出你公司的整體運營概括了。所以單號編碼必須是除了你們公司少部分人外,其他人基本看不懂的。其實最好的防泄漏編碼規則就是在編碼中不要加入任何和公司運營的數據。

3、隨機碼。

  很多人在制定單號編碼規則的時候,第一個想法肯定是不重覆唯一性,那麼第二個想法可能就是安全性,同時滿足前兩者的第三個想法,就是在單號中添加隨機碼了。在單號中添加2~3隨機碼,和流水號結合使用,可以起到隱藏流水號的真實數據的作用。

4、防止併發。

  這條規則主要針對編碼中有時間的設定。

5、控制位數。

  這點很好理解,單號的作用就是便於查詢。

 

單號幾種常規的創建方式:

    1.利用資料庫主鍵值產生一個自增長的訂單號(訂單號即數據表的主鍵)

    2.日期+自增長數字的訂單號(比如:20200101100662、202002100662、2002100662

    3.隨機生成的單號(6512353245921)

    4.字母+數字字元串式,字母應該有特殊意義。如入庫單,GD202016652

 

  訂單號設計用戶體驗規則:

   1.訂單號無重覆性;

   2.如果方便客服的話,最好是“日期+自增數”樣式的訂單號。

   3.訂單號長度儘量保持短(15位以內),方便用戶,長的號碼報錯幾率高,影響客服效率;

   4.如果你的系統用戶量在千萬級別,那麼訂單號儘量保持數字型(純整數),在資料庫訂單索引查詢中,長整數字型的數據索引與檢索效率,遠遠高於文本型。對於中小應用可以使用“字母+數字”的字元串形式!

 

五、使用存儲過程創建單號

   在使用ABP框架構項目時,如果想在倉儲層調用存儲過程,我們應該如何來實現呢?關於這個問題,我搜索了很多資料,最後還看了官方文檔:https://aspnetboilerplate.com/Pages/Documents/Articles/Using-Stored-Procedures,-User-Defined-Functions-and-Views/index.html

在看完官方文檔,對於如何在ABP中使用存儲過程已經有了一個相應的思路。現在我們來實現。

  1. Visual Studio 2017的“解決方案資源管理器”中,右鍵單擊“ABP.TPLMS.Core”項目的“IRepositories”文件夾,在彈出菜單中選擇“添加” >  “類”,在彈出對話框中選擇“介面”, 介面命名為 IInStockOrderRepository,然後選擇“添加”。如下圖。

 

    2.在IInStockOrderRepository介面定義我們需要用到的方法,代碼如下。

using Abp.Domain.Repositories;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Data.Common;
using System.Linq;
using System.Text;
using ABP.TPLMS.Entitys;
using System.Threading.Tasks;
using Abp.Dependency; 

namespace ABP.TPLMS.IRepositories
{

    public interface IInStockOrderRepository : IRepository<InStockOrder,int>, ITransientDependency
    {

        /// <summary>
        /// 執行給定的命令
        /// </summary>
        /// <param name="sql">命令字元串</param>
        /// <param name="parameters">要應用於命令字元串的參數</param>
        /// <returns>執行命令後由資料庫返回的結果</returns>
        int Execute(string sql, params object[] parameters);

        /// <summary>
        /// 創建一個原始 SQL 查詢,該查詢將返回給定泛型類型的元素。
        /// </summary>
        /// <typeparam name="T">查詢所返回對象的類型</typeparam>
        /// <param name="sql">SQL 查詢字元串</param>
        /// <param name="parameters">要應用於 SQL 查詢字元串的參數</param>
        /// <returns></returns>

        IQueryable<T> SqlQuery<T>(string sql, params object[] parameters);

        DbCommand CreateCommand(string commandText, CommandType commandType, params object[] parameters);

        /// <summary>
        /// 創建單號
        /// </summary>
        /// <param name="name">單證名稱代碼</param>
        /// <returns></returns>

        string GetNo(string name);

        /// <summary>
        /// 導入貨物信息
        /// </summary>
        /// <param name="ids">導入貨物的ID集合</param>
        /// <param name="no">單號</param>
        void ImportCargo(string ids,string no);

    }
}
       3. Visual Studio 2017的“解決方案資源管理器”中,右鍵單擊“ABP.TPLMS.EntityFrameworkCore”項目的“Repositories”文件夾,在彈出菜單中選擇“添加” >  “類” 命名為 InStockOrderRepository,並繼承IInStockOrderRepository介面。實現介面中的方法。代碼如下。
using Abp.Data;
using Abp.Dependency;
using Abp.Domain.Entities;
using Abp.EntityFrameworkCore;
using ABP.TPLMS.Entitys;

using ABP.TPLMS.IRepositories;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;

using System.Data;
using System.Data.Common;
using System.Data.SqlClient;

using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
 

namespace ABP.TPLMS.EntityFrameworkCore.Repositories
{

    public class InStockOrderRepository : TPLMSRepositoryBase<InStockOrder, int> ,IInStockOrderRepository, ITransientDependency
    {

        private readonly IActiveTransactionProvider _transactionProvider; 

        public InStockOrderRepository(IDbContextProvider<TPLMSDbContext> dbContextProvider) : base(dbContextProvider)
        { }

        protected InStockOrderRepository(IDbContextProvider<TPLMSDbContext> dbContextProvider, IActiveTransactionProvider transactionProvider)
            : base(dbContextProvider)
        {

            _transactionProvider = transactionProvider;
        }

        public DbCommand CreateCommand(string commandText, CommandType commandType, params SqlParameter[] parameters)
        {

            EnsureConnectionOpen();
            var dbFacade = Context.Database;

            var connection = Microsoft.EntityFrameworkCore.RelationalDatabaseFacadeExtensions.GetDbConnection(dbFacade);
            var command = connection.CreateCommand();
            command.CommandText = commandText;
            command.CommandType = commandType;
            command.Transaction = GetActiveTransaction();

            foreach (var parameter in parameters)
            {
                command.Parameters.Add(parameter);

            }
            return command;

        }

        DbCommand IInStockOrderRepository.CreateCommand(string commandText, CommandType commandType, params object[] parameters)
        {

            EnsureConnectionOpen();
            var dbFacade = Context.Database;
            var connection = Microsoft.EntityFrameworkCore.RelationalDatabaseFacadeExtensions.GetDbConnection(dbFacade);
 

            var command = connection.CreateCommand();
            command.CommandText = commandText;
            command.CommandType = commandType;
            command.Transaction = GetActiveTransaction();
            foreach (var parameter in parameters)
            {
                command.Parameters.Add(parameter);

            }
            return command;
        }

 

        private void EnsureConnectionOpen()
        {

            var dbFacade = Context.Database;
            var connection = Microsoft.EntityFrameworkCore.RelationalDatabaseFacadeExtensions.GetDbConnection(dbFacade);

            if (connection.State != ConnectionState.Open)
            {
                connection.Open();
            }

        }

        int IInStockOrderRepository.Execute(string sql, params object[] parameters)
        {
            throw new NotImplementedException();

        }

        private DbTransaction GetActiveTransaction()
        {
            return (DbTransaction)_transactionProvider.GetActiveTransaction(new ActiveTransactionProviderArgs
            {
                {"ContextType", typeof(TPLMSDbContext) },
                {"MultiTenancySide", MultiTenancySide }
            });

        }
 

         string IInStockOrderRepository.GetNo(string name)
        {       

            SqlParameter[] parameters = {
                 new SqlParameter("Name",System.Data.SqlDbType.NVarChar,10),
                 new SqlParameter("BH", System.Data.SqlDbType.NVarChar,20)

                                          };

            parameters[0].Value = name;
            parameters[1].Direction = System.Data.ParameterDirection.Output;

            int cnt = Context.Database.ExecuteSqlCommand(
 "EXEC p_NextBH @Name, @BH output",
parameters);

            string no = parameters[1].Value.ToString();

            if (cnt < 0)
            {
                no = string.Empty;
            }
            return no;
        }

 

        void IInStockOrderRepository.ImportCargo(string ids,string no)
        {

            SqlParameter[] parameters = {
                new SqlParameter("id",System.Data.SqlDbType.VarChar,500),
                new SqlParameter("No", System.Data.SqlDbType.NVarChar,20)

         };

            parameters[0].Value = ids + ",";
            parameters[1].Value = no;
            int cnt = Context.Database.ExecuteSqlCommand(
 "EXEC SP_ImportCargo2GDE @id, @No",
parameters);
        }

        IQueryable<T> IInStockOrderRepository.SqlQuery<T>(string sql, params object[] parameters)
        {
            throw new NotImplementedException();
        }
    }
}

 

   4.在這裡我一共使用了兩個存儲過程,p_NextBH SP_ImportCargo2GDE

   5.定義一張表TPLMS_NO,專門用來存放存所有需要唯一單號的單號的類型,以及類單號當前所使用到最大值。

CREATE TABLE [dbo].[TPLMS_NO](
[Name] [nvarchar](10) NOT NULL,
[Head] [nvarchar](10) NOT NULL,
[CurrentNo] [int] NOT NULL,
[BHLen] [bigint] NOT NULL,
[IsYear] [int] NOT NULL,
[DESCRIPTION] [nvarchar](50) NULL,
PRIMARY KEY CLUSTERED 
(
[Name] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO
ALTER TABLE [dbo].[TPLMS_NO] ADD  DEFAULT ('') FOR [Head]

GO
ALTER TABLE [dbo].[TPLMS_NO] ADD  DEFAULT ((0)) FOR [CurrentNo]

GO
ALTER TABLE [dbo].[TPLMS_NO] ADD  DEFAULT ((6)) FOR [BHLen]

GO
ALTER TABLE [dbo].[TPLMS_NO] ADD  DEFAULT ((1)) FOR [IsYear]

GO
INSERT INTO [TPLMS_NO]([Name],[Head],[CurrentNo] ,[BHLen],[IsYear],[DESCRIPTION]) VALUES  ('GDE','GD',0,6,1,'入庫單')

GO
INSERT INTO [TPLMS_NO]([Name],[Head],[CurrentNo],[BHLen],[IsYear],[DESCRIPTION])
VALUES ('BAT','A' ,0,7,0,'批次號')

GO
       6.由於這是一個小應用,所以單號的生成就是字母+日期+流水號。通過p_NextBH來實現單號的創建,專門用來在上一步的表中取單號。p_NextBH這個存儲過程的實現如下:

 

--獲取新編號的存儲過程

CREATE PROC [dbo].[p_NextBH]
@Name nvarchar(10),           --編號種類
@BH nvarchar(20) OUTPUT --新編號
AS

BEGIN TRAN
UPDATE [TPLMS_NO] WITH(ROWLOCK) SET 
@BH=Head+case isyear when 1 then convert(varchar(4),year(getdate())) else '' end 
+RIGHT(POWER(convert(bigint,10),BHLen)+CurrentNo+1,BHLen),
CurrentNo=CurrentNo+1
WHERE Name=@Name
select @BH

COMMIT TRAN
GO

     7. 關於使用p_NextBH這個存儲過程生成單號有什麼優缺點呢?在存儲過程中使用事物,資料庫的性能會急劇下滑。對於小應用來說,這並不是太大的問題,對於中大型應用來說,就可能是問題了。可以直接使用UPDATE獲取到的更新鎖,即SQL SERVER會保證UPDATE的順序執行。適用中型應用,但是無法滿足高併發性能要求。我們來改一下存儲過程。

--獲取新編號的存儲過程
CREATE PROC [dbo].[p_NextBH]
@Name nvarchar(10),           --編號種類
@BH nvarchar(20) OUTPUT --新編號

AS

UPDATE [TPLMS_NO] WITH(ROWLOCK) SET 
@BH=Head+case isyear when 1 then convert(varchar(4),year(getdate())) else '' end 
+RIGHT(POWER(convert(bigint,10),BHLen)+CurrentNo+1,BHLen),
CurrentNo=CurrentNo+1
WHERE Name=@Name

select @BH

GO

 

 

    8. 通過傳遞貨物信息的ID,把貨物信息導入到入庫單中,這個功能通過存儲過程SP_ImportCargo2GDE來實現。這個存儲過程的實現如下:

CREATE Proc [dbo].[SP_ImportCargo2GDE]
@id varchar(1000),           --id集合
@No nvarchar(20)  --單號

as 
 

CREATE TABLE #IdTable(Id int  NULL) 

DECLARE @PointerPrev int
    DECLARE @PointerCurr int
    DECLARE @TName nvarchar(100)
    Set @PointerPrev=1
    while (@PointerPrev < LEN(@id))
    Begin

        Set @PointerCurr=CharIndex(',',@id,@PointerPrev)
        if(@PointerCurr>0)
        Begin

            set @TName=SUBSTRING(@id,@PointerPrev,@PointerCurr-@PointerPrev)         --如果作為查詢條件,我需要創建一個臨時表,將數據插入進去
         insert into #IdTable (Id) VALUES (convert(int,@TName))
         SET @PointerPrev = @PointerCurr+1

        End
        else
            Break
    End 

DECLARE @BH nvarchar(20),@batch varchar(20),@maxseqno int
select @BH=@No
select @maxseqno=isnull(MAX(seqno),0) from [InStockOrderDetail] where InStockNo= @BH

--創建批次號

EXEC [dbo].[p_NextBH] 'BAT', @batch OUTPUT 

INSERT INTO [dbo].[InStockOrderDetail]
           ([InStockNo],[SeqNo],[SupplierId],[CargoCode],[HSCode],[CargoName],[Spcf]
           ,[Unit],[Country],[Brand] ,[Curr],[Package],[Length],[Width],[Height],[Qty]
           ,[Vol],[LawfQty],[SecdLawfQty],[Price],[TotalAmt],[GrossWt],[NetWt]
           ,[LawfUnit] ,[SecdLawfUnit],[Batch],[DeliveryOrderDetailId],[CreationTime])

   SELECT @BH,convert(int,seqno)+@maxseqno,a.supplierid,[CargoCode],[HSCode],[CargoName],[Spcf]
         ,[Unit],[Country],[Brand],[Curr]  ,[Package],[Length],[Width],[Height],0 [Qty]
 ,[Vol] ,0 [LawfQty], 0 [SecdLawfQty] ,[Price],0 [TotalAmt],[GrossWt],[NetWt]
 ,'' [LawfUnit],'' [SecdLawfUnit],@batch,a.id,getdate()
  FROM 
  (select row_number() OVER  ( order by id) seqno,* from [dbo].Cargos
   where id in (select id from #IdTable
  where  id not in (select [DeliveryOrderDetailId] 
  from [InStockOrderDetail]
  where InStockNo= @BH
  )
  )   
  ) a 

drop 

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一.目標 SpringBoot整合Mybatis對單表的增、刪、改、查操作 二.開發工具及項目環境 IDE: IntelliJ IDEA 2019.3 SQL: Navicat for MySQL 三.基礎環境配置 1. 創建資料庫: demodb 2. 創建數據表及插入數據 3. 必備Maven依 ...
  • 做Android手機系統或App測試的過程中, 如果碰到了bug,開發一般會需要測試人員提供當時的bug截圖, 如何用Python 批處理腳本, 快速實現截圖呢? 準備階段 1. adb shell screencap p /sdcard/a.png 命令, 可以實現手機截圖並保存到/sdcard/ ...
  • 基於 Redis 實現 CAS 操作 Intro 在 .NET 里併發情況下我們可以使用 來實現 CAS (Compare And Swap) 操作,在分散式的情景下很多時候我們都會使用 Redis ,最近在改之前做的一個微信小游戲項目,之前是單機運行的,有些數據存儲是基於記憶體的,直接基於對象操作的 ...
  • Main函數代碼 using System; namespace ConsoleApp4 { class Program { public static void Main(string[] args) { Console.WriteLine(args[0]); Console.WriteLine( ...
  • VS2019 for MAC已經發佈很長時間了,本以為項目移過去很麻煩,一直沒有動作,最近呆家裡快發黴了,決定研究研究,沒想到一句代碼都不需要動,直接完功,這下可以生產了。同學們可以放心整了。 ...
  • HSQL 是一種輕量級的基於 .NET Core 的資料庫對象關係映射「ORM」框架 HSQL 是一種可以使用非常簡單且高效的方式進行資料庫操作的一種框架,通過簡單的語法,使資料庫操作不再成為難事。目前支持的資料庫有 MySql、SQLServer。 安裝方法 Install-Package HSQ ...
  • 問題: 其實也不是問題了 算是優化吧 當做net項目時 不是前後臺分離時 需要寫很多的前端頁面 這時我們就會用到很多的ui插件js,css文件 (這裡指的第三方的ui插件不是自己寫的js,css) 比如bootstrap 當我們新建一個mvc項目時 會自動下載bootstrap 但是用的多了之後 j ...
  • 前言 上一篇博客上已經實現了使用EventBus對具體事件行為的分發處理,某種程度上也算是基於事件驅動思想編程了。但是如上篇博客結尾處一樣,我們源碼的執行效率依然達不到心裡預期。在下單流程里我們明顯可以將部分行為進行非同步處理,提升下單操作的執行效率。 Redis基礎命令 Redis有兩種方式可支持我 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...