How to save bulk records as transaction to SQL ser

2019-07-28 01:55发布

I am working on a C# MVC application. In this application user is uploading data from EXCEL spreadsheet and data is showing to grid.

After it has been showing to grid, user hit 'validate data' button. Application needs to perform UI (data length, empty field, data formats, etc.) validation and additionally SQL validations are also required for eg. record should not already exists already, any constraints, etc.

After validation data is displayed to user for any errors associated with each row, so that he\she can make corrections in pasted data and then save data as a transaction to SQL server database.

One way I am thinking to do this is loop the data in the C# code and perform the validations for each row by calling some stored procedure with return statements then store the same data probably in a dataset and then display to user in the grid. Then when he Submits, perform insert statements in a loop in a transaction.

The problem is that the approach which I am thinking about will double the number of database hits.

So if there are 100 rows in the grid, it will entail 200 database hits.

I am seeking advise if there is another efficient way to do this.

1条回答
时光不老,我们不散
2楼-- · 2019-07-28 02:05

Here is my approach:

You can validate all your UI side validation on client side for example length etc. So that you don't need to travel to application as well as database server.

For data operation here is the approach which I have implemented many times.

  1. Create a table type which must have all the columns which you need to process.

  2. Use that table type variable into stored procedure as input parameter where you can pass n-number of rows in one go so that you do not need to loop at c# to hit database multiple times.

  3. User merge statement inside the stored procedure if record is not matching you can insert it and if matching you can update it if needed. You can also do this action inside the transaction.

Hope this will help you.

EDIT 1: Based on your comment for database level validation.

There would be two types of error at database side. 1. Data itself won't be in the format as is expected by sql table definition like data type conversion failed.

  1. DDL level error like data length exceeding or foreign key constrains etc.

I would recommend that do all possible validation of data you can code at c# level. Like length of data based on your destination column. Type of data before calling to stored procedure and you can filter such records at c# level. At this level you can do maximum validations.

Once you pass the data to sql server you can use try and catch in SQL server where you can implement logic of failed rows. Keep failed rows in temp table which you can return later and insert all successful.

EDIT 2: Here is the possible code.

CREATE TABLE Users
(
    Idx             BIGINT IDENTITY(1,1),
    UserID          UNIQUEIDENTIFIER,
    FirstName       VARCHAR(100),
    LastName        VARCHAR(100),
    Email           VARCHAR(100),
    UserPassword    VARCHAR(100),
    InsertDate      DATETIME,
    UpDateDate      DATETIME,
    IsActive        BIT,
 CONSTRAINT [Users_PK] PRIMARY KEY CLUSTERED 
(
    [UserID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = ON, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

SET ANSI_PADDING OFF
GO

CREATE TYPE UT_Users AS TABLE  
(  
    Idx             INT,
    FirstName       VARCHAR(100),
    LastName        VARCHAR(100),
    Email           VARCHAR(100),
    UserPassword    VARCHAR(100),
    InsertDate      DATETIME,
    UpDateDate      DATETIME,
    IsActive        BIT
) 
GO

CREATE PROCEDURE uspInsertUsers(@user_Details [UT_Users]) READONLY
AS  
BEGIN  
    DECLARE @Counter INT=1
    DECLARE @TotalRows INT=0

    SELECT @TotalRows = COUNT(1) FROM @user_Details

    WHILE @TotalRows>@Counter
        BEGIN  
            TRY
                BEGIN
                    INSERT INTO dbo.Users  
                    SELECT * FROM @user_Details WHERE @Counter = Idx
                END
            CATCH
                BEGIN
                    --write code for catching the error as per your need. Store row in temp tables and return the temp table at the end
                END
            SET @Counter = @Counter+1
        END  
END
GO
DECLARE @user_Details AS [UT_Users];

INSERT @user_Details
SELECT 1,'Rahul','Neekhra','rahul@india.com','12345',GETDATE(),GETDATE(),1 UNION
SELECT 2,'James','Streak','streak@usa.com','12345',GETDATE(),GETDATE(),1 

EXEC uspInsertUsers @user_Details
查看更多
登录 后发表回答