批量插入多个表 - C#,Sql

时间:2018-04-15 01:07:00

标签: c# asp.net sql-server

我有2个表ClassMaterial和ClassSubMatRelation。

ClassMaterial           
[ClassMaterialID] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](100) NOT NULL,
[Description] [nvarchar](1000) NULL,
[EbookLink] [nvarchar](500) NULL,
[Status_Info] [smallint] NULL DEFAULT ('1'),
[SEOTitle] [nvarchar](100) NULL,
[SEOKeyword] [nvarchar](50) NULL,
[SEODesc] [nvarchar](500) NULL

ClassSubMatRelation
[ClassSubMatRelationID] [int] IDENTITY(1,1) NOT NULL,
[BoardFK] [int] NULL,
[ClassFK] [int] NULL,
[ClassSubjectFK] [int] NOT NULL,
[MaterialTypeFK] [int] NOT NULL,
[ClassMaterialFK] [int] NOT NULL,
[Status_Info] [smallint] NOT NULL

我将ClassMaterial c#中的多条记录保存为: -

foreach (var eachMaterial in value.materialModel)
{
 DataRow dr = dt.NewRow();
 dr[Constants.Name] = eachMaterial.Heading;
 dr[Constants.Description] = eachMaterial.Descr;
 dr[Constants.EbookLink] = eachMaterial.Ebook;
 dr[Constants.SEODesc] = eachMaterial.SEODesc;
 dr[Constants.SEOTitle] = eachMaterial.SEOTitle;
 dr[Constants.SEOKeyword] = eachMaterial.SEOKeyword;

 dt.Rows.Add(dr);
}


using (SqlBulkCopy SQLbulk = new SqlBulkCopy(sqlcon))
 {
    SQLbulk.ColumnMappings.Add(Constants.Name, Constants.Name);
       SQLbulk.ColumnMappings.Add(Constants.Description, Constants.Description);
       SQLbulk.ColumnMappings.Add(Constants.EbookLink, Constants.EbookLink);
       SQLbulk.ColumnMappings.Add(Constants.SEODesc, Constants.SEODesc);
       SQLbulk.ColumnMappings.Add(Constants.SEOTitle, Constants.SEOTitle);
       SQLbulk.ColumnMappings.Add(Constants.SEOKeyword, Constants.SEOKeyword);
       SQLbulk.DestinationTableName = value.aBundleInsert.MainTblName;
       SQLbulk.WriteToServer(dt);
 }

我的问题是在ClassSubMatRelation中我有ClassMaterialFK列,它是ClassMaterial中ClassMaterialID列的外键。所以我想将ClassMaterial中插入的所有新记录的ClassMaterialIDs与其他记录一起保存到ClassSubMatRelation中。 我经历过this ques。它建议使用OUTPUT子句,但它需要大量的代码更改。我也无法理解this ques。有没有其他方法这样做?提前谢谢。

修改

所以在@Zohar的帮助下,我实现了我想要的目标: -

CREATE TYPE udt_classMaterial_base As Table
(
    classMaterial_id int,
    base_classMaterial_temp_id int,  
    [Name] [nvarchar](100) NOT NULL,
    [Description] [nvarchar](1000) NULL,
    [EbookLink] [nvarchar](500) NULL,
    [Status_Info] [smallint] NULL DEFAULT ('1'),
    [SEOTitle] [nvarchar](100) NULL,
    [SEOKeyword] [nvarchar](50) NULL,
    [SEODesc] [nvarchar](500) NULL
);

CREATE TYPE udt_classSubMatRel_related As Table
(
    related_classSubMatRel_base_id int,
    [BoardFK] [int] NULL,
    [ClassFK] [int] NULL,
    [ClassSubjectFK] [int] NOT NULL,
    [MaterialTypeFK] [int] NOT NULL,
    [ClassMaterialFK] [int] NOT NULL,
    [Status_Info] [smallint] NOT NULL
);

CREATE TYPE udt_classMaterial_idMap as table
(
    temp_id int,
    id int
)
GO  

我的程序如下: -

ALter PROCEDURE stp_InsertMultipleRecordsToMultipleTables
(
    @base as dbo.udt_classMaterial_base readonly,
    @related as dbo.udt_classSubMatRel_related readonly,
    @ReturnBool int out
)
AS
BEGIN
    SET NOCOUNT ON;
    SET XACT_ABORT ON;

BEGIN TRY
BEGIN TRANSACTION;

DECLARE @idMap as dbo.udt_classMaterial_idMap
MERGE INTO ClassMaterial USING @base AS temp ON 1 = 0 -- Always not matched
WHEN NOT MATCHED THEN
    INSERT (Name,Description,EbookLink,SEOTitle,SEOKeyword,SEODesc)
    VALUES (temp.Name,temp.Description,temp.EbookLink,temp.SEOTitle,temp.SEOKeyword,temp.SEODesc)
    OUTPUT temp.base_classMaterial_temp_id, inserted.ClassMaterialID -- Here we use the base_temp_id to map to the correct id
    INTO @idMap (temp_id, id);

INSERT INTO ClassSubMatRelation(BoardFK, ClassFK,ClassMaterialFK,ClassSubjectFK,MaterialTypeFK)
SELECT BoardFK, ClassFK, id, ClassSubjectFK,MaterialTypeFK
FROM @related r
INNER JOIN @idMap m ON(r.related_classSubMatRel_base_id = m.temp_id) -- here we use the map to insert the related records with the correct base ids
SET @ReturnBool = 1;

COMMIT TRANSACTION;
END TRY
BEGIN CATCH
    IF (XACT_STATE()) = -1  
    BEGIN  
        SET @ReturnBool = 0;
        ROLLBACK TRANSACTION;  
    END;  

    IF (XACT_STATE()) = 1  
    BEGIN  
        COMMIT TRANSACTION;     
    END;  
END CATCH

Return @ReturnBool

END GO

和C#方法: -

public int BulkInsertBoard(RequestData value)
    {
        int ReturnBool = 0;
        try
        {
            DataTable dtRel = new DataTable();
            dtRel.Columns.Add("related_classSubMatRel_base_id");
            dtRel.Columns.Add("BoardFK");
            dtRel.Columns.Add("ClassFK");
            dtRel.Columns.Add("ClassSubjectFK");
            dtRel.Columns.Add("MaterialTypeFK");
            dtRel.Columns.Add("ClassMaterialFK");
            dtRel.Columns.Add(Constants.StatusInfo);

            DataTable dt = new DataTable();
            dt.Columns.Add("classMaterial_id");
            dt.Columns.Add("base_classMaterial_temp_id");
            dt.Columns.Add(Constants.Name);
            dt.Columns.Add(Constants.Description);
            dt.Columns.Add(Constants.EbookLink);
            dt.Columns.Add(Constants.StatusInfo);
            dt.Columns.Add(Constants.SEOTitle);
            dt.Columns.Add(Constants.SEOKeyword);
            dt.Columns.Add(Constants.SEODesc);


            using (var sqlcon = new SqlConnection(Constants.Connection))
            {
                SqlDataAdapter adapter = new SqlDataAdapter("DECLARE @udt_classMaterial_base dbo.udt_classMaterial_base SELECT * FROM @udt_classMaterial_base", sqlcon);
                adapter.FillSchema(dt, SchemaType.Source);

                foreach (var eachMaterial in value.materialModel)
                {
                    DataRow dr = dt.NewRow();
                    if (dt.Columns.Contains("classMaterial_id") && dt.Columns["classMaterial_id"].DataType == typeof(int))
                        dr["classMaterial_id"] = 0;
                    if (dt.Columns.Contains("base_classMaterial_temp_id"))
                        dr["base_classMaterial_temp_id"] = 0;
                    dr[Constants.Name] = eachMaterial.Heading;
                    dr[Constants.Description] = eachMaterial.Descr;
                    if (dt.Columns.Contains(Constants.EbookLink) && dt.Columns[Constants.EbookLink].DataType == typeof(string))
                        dr[Constants.EbookLink] = eachMaterial.Ebook;
                    dr[Constants.StatusInfo] = Convert.ToInt16(1);
                    if (!string.IsNullOrEmpty(eachMaterial.SEODesc))
                        dr[Constants.SEODesc] = eachMaterial.SEODesc;
                    if (!string.IsNullOrEmpty(eachMaterial.SEOTitle))
                        dr[Constants.SEOTitle] = eachMaterial.SEOTitle;
                    if (!string.IsNullOrEmpty(eachMaterial.SEOKeyword))
                        dr[Constants.SEOKeyword] = eachMaterial.SEOKeyword;

                    dt.Rows.Add(dr);
                }

                SqlDataAdapter adapterRel = new SqlDataAdapter("DECLARE @udt_classSubMatRel_related dbo.udt_classSubMatRel_related SELECT * FROM @udt_classSubMatRel_related", sqlcon);
                adapterRel.FillSchema(dtRel, SchemaType.Source);


                DataRow drRel = dtRel.NewRow();
                if (dtRel.Columns.Contains("related_classSubMatRel_base_id"))
                    drRel["related_classSubMatRel_base_id"] = 0;
                drRel["BoardFK"] = value.aBundleInsert.BoardFK;
                drRel["ClassFK"] = value.aBundleInsert.ClassesFK;
                drRel["ClassSubjectFK"] = value.aBundleInsert.ClassSubjectFK;
                drRel["MaterialTypeFK"] = value.aBundleInsert.MaterialIndicator;
                if (dtRel.Columns.Contains("ClassMaterialFK"))
                    drRel["ClassMaterialFK"] = value.aBundleInsert.MaterialFetchID;
                drRel[Constants.StatusInfo] = Convert.ToInt16(1);

                dtRel.Rows.Add(drRel);

                using (SqlCommand cmd = new SqlCommand(Constants.ProcNameBulkInsertBoard))
                {
                    cmd.Connection = sqlcon;
                    cmd.CommandType = CommandType.StoredProcedure;
                    if (sqlcon.State == System.Data.ConnectionState.Closed)
                    {
                        sqlcon.Open();
                    }
                    cmd.Parameters.AddWithValue("@base", dt);
                    cmd.Parameters.AddWithValue("@related", dtRel);
                    SqlParameter outputParam = new SqlParameter();
                    outputParam.ParameterName = "@ReturnBool";
                    outputParam.SqlDbType = System.Data.SqlDbType.Int;
                    outputParam.Direction = System.Data.ParameterDirection.Output;
                    cmd.Parameters.Add(outputParam);

                    cmd.ExecuteNonQuery();

                    if (!cmd.Parameters["@ReturnBool"].Value.Equals(DBNull.Value))
                    {
                        ReturnBool = Convert.ToInt32(cmd.Parameters["@ReturnBool"].Value);
                    }

                }
            }
            //using (SqlBulkCopy SQLbulk = new SqlBulkCopy(sqlcon))
            //{
            //    SQLbulk.ColumnMappings.Add(Constants.Name, Constants.Name);
            //    SQLbulk.ColumnMappings.Add(Constants.Description, Constants.Description);
            //    SQLbulk.ColumnMappings.Add(Constants.EbookLink, Constants.EbookLink);
            //    SQLbulk.ColumnMappings.Add(Constants.SEODesc, Constants.SEODesc);
            //    SQLbulk.ColumnMappings.Add(Constants.SEOTitle, Constants.SEOTitle);
            //    SQLbulk.ColumnMappings.Add(Constants.SEOKeyword, Constants.SEOKeyword);
            //    SQLbulk.DestinationTableName = value.aBundleInsert.MainTblName;
            //    SQLbulk.WriteToServer(dt);
            //}
        }
        catch (Exception ex)
        {
            string error = ex.Message;
            return ReturnBool;
            //return new JsonResult { Data = ex.Message, JsonRequestBehavior=JsonRequestBehavior.AllowGet };
        }

        return ReturnBool;
    }

希望这能帮助有需要的人。

0 个答案:

没有答案