zoukankan      html  css  js  c++  java
  • SqlDataAdapter 更新插入 与 InsertBulkCopy

    近日做项目,涉及多个数据库多个表的关联更新,因数据量巨大,逐条更新也很费时。于是就想用SqlDataAdapter 一次提交一批数据过去。以下是自己经历的坑:

    1. table Merge 部分

     DataTable dtCBBill = DbHelper.ExecuteDataAdapter(SqlHelper.cbBill, pars, strConnOldCBBill);
     DataTable dtMember = DbHelper.ExecuteDataAdapter(SqlHelper.accounts_m, null, strConnMember);
     DataTable dtUser = DbHelper.ExecuteDataAdapter(SqlHelper.accounts_u2, null, strConnWeb);
     //筛选出有账单的用户
     DataTable dtM = (from c in dtMember.AsEnumerable()
                       join r in dtCBBill.AsEnumerable() on c["f_accounts"] equals r["f_accounts"]
                       select c).CopyToDataTable();
     DataTable dtU = (from c in dtUser.AsEnumerable()
                       join r in dtCBBill.AsEnumerable() on c["f_accounts"] equals r["f_accounts"]
                       select c).CopyToDataTable();
     //设置主键加快合并速度
     SetPrimaryKey(dtCBBill);
     SetPrimaryKey(dtM);
     SetPrimaryKey(dtU);
     MergeTable(dtM, dtCBBill);
     MergeTable(dtU, dtCBBill);
    。。。。dtContribution

    Merge提示<target>.f_CBMoney 和 <source>.f_CBMoney 的属性冲突: DataType 属性不匹配。几经调试,发现,源dtCBBill的一个字段是decimal,而对应合并的目的表dtContribution相应字段是int 类型。修改sql语句,cast(某字段 as int) 解决此类异常。网上有说

    在调用dt1.Merge(dt2)的时候,由于两个serverid字段类型不一致,一个int32,一个int64,导致无法Merge。用importRow的方式就可以合并了:

    private DataTable MergeTable(DataTable dest, DataTable source)
    {
          DataRow[] sourceRows = source.Select();
          for (int i = 0; i < sourceRows.Length; i++)
          {
              dest.ImportRow(sourceRows[i]);
           }
           return dest;
     }

    这种方法需要改动代码多,就没有尝试。
    2. InsertBulkCopy 部分

    public static int InsertBulkCopy(string connectionString, DataTable dt,string destTable)
    {
        using (SqlConnection Connection = new SqlConnection(connectionString))
        {
            Connection.Open();
            using (SqlTransaction transaction = Connection.BeginTransaction())
            {
                using (SqlBulkCopy sqlbulkcopy = new SqlBulkCopy((SqlConnection)Connection, SqlBulkCopyOptions.KeepIdentity, transaction))
                {
                   sqlbulkcopy.DestinationTableName = destTable;
                   for (int i = 0; i < dt.Columns.Count; i++)
                   {
                       sqlbulkcopy.ColumnMappings.Add(dt.Columns[i].ColumnName, dt.Columns[i].ColumnName);
                    }
                    sqlbulkcopy.BatchSize = 10000;
                    try
                    {
                        sqlbulkcopy.WriteToServer(dt);
                        transaction.Commit();
                        return 1;
                     }
                     catch(Exception ex)
                     {
                        transaction.Rollback();
                        return 0;
                     }
                  }
            }
        }
    }

    必须要保证 source table 与 destination table 字段完全一致,包括字段的大小写。因为大小写不一样,如 f_employee 与 f_Employee,直接会导致插入失败。

    3. 最重要的 SqlDataAdapter

    SqlDataAdapter adapter = new SqlDataAdapter();
    SqlConnection conn = new SqlConnection(strConnCash);
    adapter.SelectCommand = new SqlCommand(SqlHelper.selCmdText, conn);
    SqlParameter parameter1 = adapter.SelectCommand.Parameters.Add("@f_date", SqlDbType.DateTime);
    parameter1.Value = date;
    
    DataTable dtContri = new DataTable();
    adapter.Fill(dtContri);
    
    adapter.UpdateBatchSize = 1000;
    adapter.UpdateCommand = new SqlCommand(SqlHelper.updCmdText, conn);
    adapter.UpdateCommand.Parameters.Add("@f_CBMoney", SqlDbType.Int, 4, "f_CBMoney");
    adapter.UpdateCommand.Parameters.Add("@f_CBMresult", SqlDbType.Int, 4, "f_CBMresult");
    adapter.UpdateCommand.Parameters.Add("@f_CBNum", SqlDbType.Int, 4, "f_CBNum");
    SqlParameter[] paramters = new SqlParameter[]
    {
           new SqlParameter("@f_date",SqlDbType.DateTime,8,"f_date"),
           new SqlParameter("@f_accounts",SqlDbType.VarChar,20,"f_accounts")
    };
    paramters[0].SourceVersion = DataRowVersion.Original;
    paramters[1].SourceVersion = DataRowVersion.Original;
                                adapter.UpdateCommand.Parameters.AddRange(paramters);
    adapter.UpdateCommand.UpdatedRowSource = UpdateRowSource.None;
    
    adapter.InsertCommand = new SqlCommand(SqlHelper.insCmdText, conn);
    adapter.InsertCommand.Parameters.Add("@f_accounts", SqlDbType.VarChar, 20, "f_accounts");
    adapter.InsertCommand.Parameters.Add("@f_date", SqlDbType.DateTime, 4, "f_date");
    adapter.InsertCommand.Parameters.Add("@f_CBMoney", SqlDbType.Int, 4, "f_CBMoney");
    adapter.InsertCommand.Parameters.Add("@f_CBMresult", SqlDbType.Int, 4, "f_CBMresult");
    adapter.InsertCommand.Parameters.Add("@f_CBNum", SqlDbType.Int, 4, "f_CBNum");
                                adapter.InsertCommand.Parameters.Add("@f_StupeSurplus", SqlDbType.Int, 4, "f_StupeSurplus");
    adapter.InsertCommand.Parameters.Add("@f_status", SqlDbType.TinyInt, 1, "f_status");
    adapter.InsertCommand.UpdatedRowSource = UpdateRowSource.None;
    
    //将ds数据同步到dtContri表
    SetPrimaryKey(dtContri);
    MergeTableManual( dtCBBill,ref dtContri);                           
                            
    //执行更新插入                           
    int r = adapter.Update(dtContri);
    log.Info(site + " CB update&insert: " + r);
    /// <summary>
    /// 设置主键
    /// </summary>
    /// <param name="dt"></param>
    private void SetPrimaryKey(DataTable dt)
    {
       dt.PrimaryKey = new DataColumn[] { dt.Columns["f_accounts"] };
    }
    
    /// <summary>
    /// 合并表数据
    /// </summary>
    /// <param name="source"></param>
    /// <param name="target"></param>
    private void MergeTable(DataTable source, DataTable target, bool isAddSchema = true)
    {
        target.Merge(source, false, isAddSchema ? MissingSchemaAction.Add : MissingSchemaAction.Ignore);
    }
    
    /// <summary>
    /// 手动合并表数据
    /// </summary>
    /// <param name="source"></param>
    /// <param name="target"></param>
    private void MergeTableManual(DataTable source,ref DataTable target)
    {
       foreach (DataRow item in source.Rows)
       {
          var row = target.Rows.Find(item["f_accounts"]);            
          if (row != null)
          {
             row["f_CBMoney"] = item["f_CBMoney"];
             row["f_CBMresult"] = item["f_CBMresult"];
             row["f_CBNum"] = item["f_CBNum"];
           }
           else
           {
              var newRow = target.NewRow();
              newRow["f_accounts"] = item["f_accounts"];
              newRow["f_date"] = item["f_date"];
              newRow["f_CBMoney"] = item["f_CBMoney"];
              newRow["f_CBMresult"] = item["f_CBMresult"];
              newRow["f_CBNum"] = item["f_CBNum"];
              newRow["f_StupeSurplus"] = item["f_StupeSurplus"];
              newRow["f_status"] = item["f_status"];
              target.Rows.Add(newRow);
            }
        } 
    }

    这其中坑最多。按照 https://msdn.microsoft.com/en-us/library/wkk7s5zk(v=vs.110).aspx  这篇最有价值的文章,发现日志记录更新数目总是为0。 然后自己又做个demo,一点一点拆开研究,dataTable.SaveChanges 只是把源表最近的更新同步到离线表中,不可用。但离线表,取其中的一DataRow,改变下数据,甚至原数据再更新都能Update成功,最后通过打印RowState属性值,得到,用dataTable1.Merge(dataTable2,...)方式合并来的数据,RowState 为unchanged。遂手动Merge。运行,OK。终于搞定了。

  • 相关阅读:
    TP6框架中如何无刷新上传文件
    TP6框架设置验证码的宽度和高度后,验证码显示不全
    TP6模板缓存问题
    TP6管理后台实战第五天文章管理
    20211027技术人为什么建议写博客
    TP6管理后台实战第六天系统管理
    博客园自定义菜单
    xcat无法连接服务器
    lsf安装后配置
    xcat网络无盘启动——添加自定义安装包
  • 原文地址:https://www.cnblogs.com/dennysong/p/7291847.html
Copyright © 2011-2022 走看看