婷婷久久综合九色综合,欧美成色婷婷在线观看视频,偷窥视频一区,欧美日本一道道一区二区

<tt id="bu9ss"></tt>
  • <span id="bu9ss"></span>
  • <pre id="bu9ss"><tt id="bu9ss"></tt></pre>
    <label id="bu9ss"></label>

    當(dāng)前位置:首頁 >  站長 >  數(shù)據(jù)庫 >  正文

    SQL Server 批量插入數(shù)據(jù)的完美解決方案

     2020-12-17 15:20  來源: 腳本之家   我來投稿 撤稿糾錯

      阿里云優(yōu)惠券 先領(lǐng)券再下單

    這篇文章主要介紹了SQL Server 批量插入數(shù)據(jù)的完美解決方案,需要的朋友可以參考下

    目錄

    一、Sql Server插入方案介紹

    二、SqlBulkCopy封裝代碼

    1.方法介紹

    2.實現(xiàn)原理

    3.完整代碼

    三、測試封裝代碼

    1.測試代碼

    四、代碼下載

    一、Sql Server插入方案介紹

    關(guān)于 SqlServer 批量插入的方式,有三種比較常用的插入方式,Insert、BatchInsert、SqlBulkCopy,下面我們對比以下三種方案的速度

    1.普通的Insert插入方法

    public static void Insert(IEnumerable<Person> persons)
    {
      using (var con = new SqlConnection("Server=.;Database=DemoDataBase;User ID=sa;Password=8888;"))
      {
        con.Open();
        foreach (var person in persons)
        {
          using (var com = new SqlCommand(
            "INSERT INTO dbo.Person(Id,Name,Age,CreateTime,Sex)VALUES(@Id,@Name,@Age,@CreateTime,@Sex)",
            con))
          {
            com.Parameters.AddRange(new[]
            {
              new SqlParameter("@Id", SqlDbType.BigInt) {Value = person.Id},
              new SqlParameter("@Name", SqlDbType.VarChar, 64) {Value = person.Name},
              new SqlParameter("@Age", SqlDbType.Int) {Value = person.Age},
              new SqlParameter("@CreateTime", SqlDbType.DateTime)
                {Value = person.CreateTime ?? (object) DBNull.Value},
              new SqlParameter("@Sex", SqlDbType.Int) {Value = (int)person.Sex},
            });
            com.ExecuteNonQuery();
          }
        }
      }
    }

    2.拼接BatchInsert插入語句

    public static void BatchInsert(Person[] persons)
    {
      using (var con = new SqlConnection("Server=.;Database=DemoDataBase;User ID=sa;Password=8888;"))
      {
        con.Open();
        var pageCount = (persons.Length - 1) / 1000 + 1;
        for (int i = 0; i < pageCount; i++)
        {
          var personList = persons.Skip(i * 1000).Take(1000).ToArray();
          var values = personList.Select(p =>
            $"({p.Id},'{p.Name}',{p.Age},{(p.CreateTime.HasValue ? $"'{p.CreateTime:yyyy-MM-dd HH:mm:ss}'" : "NULL")},{(int) p.Sex})");
          var insertSql =
            $"INSERT INTO dbo.Person(Id,Name,Age,CreateTime,Sex)VALUES{string.Join(",", values)}";
          using (var com = new SqlCommand(insertSql, con))
          {
            com.ExecuteNonQuery();
          }
        }
      }
    }

    3.SqlBulkCopy插入方案

    public static void BulkCopy(IEnumerable<Person> persons)
    {
      using (var con = new SqlConnection("Server=.;Database=DemoDataBase;User ID=sa;Password=8888;"))
      {
        con.Open();
        var table = new DataTable();
        table.Columns.AddRange(new []
        {
          new DataColumn("Id", typeof(long)),
          new DataColumn("Name", typeof(string)),
          new DataColumn("Age", typeof(int)),
          new DataColumn("CreateTime", typeof(DateTime)),
          new DataColumn("Sex", typeof(int)),
        });
        foreach (var p in persons)
        {
          table.Rows.Add(new object[] {p.Id, p.Name, p.Age, p.CreateTime, (int) p.Sex});
        }

        using (var copy = new SqlBulkCopy(con))
        {
          copy.DestinationTableName = "Person";
          copy.WriteToServer(table);
        }
      }
    }

    3.三種方案速度對比

    兩者插入效率對比,Insert明顯比SqlBulkCopy要慢太多,大概20~40倍性能差距,下面我們將SqlBulkCopy封裝一下,讓批量插入更加方便

    二、SqlBulkCopy封裝代碼

    1.方法介紹

    批量插入擴(kuò)展方法簽名

    這個方法主要解決了兩個問題:

    免去了手動構(gòu)建DataTable或者IDataReader接口實現(xiàn)類,手動構(gòu)建的轉(zhuǎn)換比較難以維護(hù),如果修改字段就得把這些地方都進(jìn)行修改,特別是還需要將枚舉類型特殊處理,轉(zhuǎn)換成他的基礎(chǔ)類型(默認(rèn)int)

    不用親自創(chuàng)建SqlBulkCopy對象,和配置數(shù)據(jù)庫列的映射,和一些屬性的配置

    此方案也是在我公司中使用,以滿足公司的批量插入數(shù)據(jù)的需求,例如第三方的對賬數(shù)據(jù)此方法使用的是Expression動態(tài)生成數(shù)據(jù)轉(zhuǎn)換函數(shù),其效率和手寫的原生代碼差不多,和原生手寫代碼相比,多余的轉(zhuǎn)換損失很小【最大的性能損失都是在值類型拆裝箱上】

    此方案和其他網(wǎng)上的方案有些不同的是:不是將List先轉(zhuǎn)換成DataTable,然后寫入SqlBulkCopy的,而是使用一個實現(xiàn)IDataReader的讀取器包裝List,每往SqlBulkCopy插入一行數(shù)據(jù)才會轉(zhuǎn)換一行數(shù)據(jù)

    IDataReader方案和DataTable方案相比優(yōu)點

    效率高:DataTable方案需要先完全轉(zhuǎn)換后,才能交由SqlBulkCopy寫入數(shù)據(jù)庫,而IDataReader方案可以邊轉(zhuǎn)換邊交給SqlBulkCopy寫入數(shù)據(jù)庫(例如:10萬數(shù)據(jù)插入速度可提升30%)

    占用內(nèi)存少:DataTable方案需要先完全轉(zhuǎn)換后,才能交由SqlBulkCopy寫入數(shù)據(jù)庫,需要占用大量內(nèi)存,而IDataReader方案可以邊轉(zhuǎn)換邊交給SqlBulkCopy寫入數(shù)據(jù)庫,無須占用過多內(nèi)存

    強(qiáng)大:因為是邊寫入邊轉(zhuǎn)換,而且EnumerableReader傳入的是一個迭代器,可以實現(xiàn)持續(xù)插入數(shù)據(jù)的效果

    2.實現(xiàn)原理

    ① 實體Model與表映射

    數(shù)據(jù)庫表代碼

    CREATE TABLE [dbo].[Person](
     [Id] [BIGINT] NOT NULL,
     [Name] [VARCHAR](64) NOT NULL,
     [Age] [INT] NOT NULL,
     [CreateTime] [DATETIME] NULL,
     [Sex] [INT] NOT NULL,
    PRIMARY KEY CLUSTERED
    (
     [Id] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
    ) ON [PRIMARY]

    實體類代碼

    public class Person
    {
      public long Id { get; set; }
      public string Name { get; set; }
      public int Age { get; set; }
      public DateTime? CreateTime { get; set; }
      public Gender Sex { get; set; }
    }

    public enum Gender
    {
      Man = 0,
      Woman = 1
    }

    創(chuàng)建字段映射【如果沒有此字段映射會導(dǎo)致數(shù)據(jù)填錯位置,如果類型不對還會導(dǎo)致報錯】【因為:沒有此字段映射默認(rèn)是按照列序號對應(yīng)插入的】

    創(chuàng)建映射使用的SqlBulkCopy類型的ColumnMappings屬性來完成,數(shù)據(jù)列與數(shù)據(jù)庫中列的映射

    //創(chuàng)建批量插入對象
    using (var copy = new SqlBulkCopy(connection, options, externalTransaction))
    {
      foreach (var column in ModelToDataTable<TModel>.Columns)
      {
        //創(chuàng)建字段映射
        copy.ColumnMappings.Add(column.ColumnName, column.ColumnName);
      }
    }

    ② 實體轉(zhuǎn)換成數(shù)據(jù)行

    將數(shù)據(jù)轉(zhuǎn)換成數(shù)據(jù)行采用的是:反射+Expression來完成

    其中反射是用于獲取編寫Expression所需程序類,屬性等信息

    其中Expression是用于生成高效轉(zhuǎn)換函數(shù)其中ModelToDataTable類型利用了靜態(tài)泛型類特性,實現(xiàn)泛型參數(shù)的緩存效果

    在ModelToDataTable的靜態(tài)構(gòu)造函數(shù)中,生成轉(zhuǎn)換函數(shù),獲取需要轉(zhuǎn)換的屬性信息,并存入靜態(tài)只讀字段中,完成緩存

    ③ 使用IDataReader插入數(shù)據(jù)的重載

    EnumerableReader是實現(xiàn)了IDataReader接口的讀取類,用于將模型對象,在迭代器中讀取出來,并轉(zhuǎn)換成數(shù)據(jù)行,可供SqlBulkCopy讀取

    SqlBulkCopy只會調(diào)用三個方法:GetOrdinal、Read、GetValue其中GetOrdinal只會在首行讀取每個列所代表序號【需要填寫:SqlBulkCopy類型的ColumnMappings屬性】

    其中Read方法是迭代到下一行,并調(diào)用ModelToDataTable.ToRowData.Invoke()來將模型對象轉(zhuǎn)換成數(shù)據(jù)行object[]其中GetValue方法是獲取當(dāng)前行指定下標(biāo)位置的值

    3.完整代碼

    擴(kuò)展方法類

     public static class SqlConnectionExtension
      {
        /// <summary>
        /// 批量復(fù)制
        /// </summary>
        /// <typeparam name="TModel">插入的模型對象</typeparam>
        /// <param name="source">需要批量插入的數(shù)據(jù)源</param>
        /// <param name="connection">數(shù)據(jù)庫連接對象</param>
        /// <param name="tableName">插入表名稱【為NULL默認(rèn)為實體名稱】</param>
        /// <param name="bulkCopyTimeout">插入超時時間</param>
        /// <param name="batchSize">寫入數(shù)據(jù)庫一批數(shù)量【如果為0代表全部一次性插入】最合適數(shù)量【這取決于您的環(huán)境,尤其是行數(shù)和網(wǎng)絡(luò)延遲。就個人而言,我將從BatchSize屬性設(shè)置為1000行開始,然后看看其性能如何。如果可行,那么我將使行數(shù)加倍(例如增加到2000、4000等),直到性能下降或超時。否則,如果超時發(fā)生在1000,那么我將行數(shù)減少一半(例如500),直到它起作用為止?!?lt;/param>
        /// <param name="options">批量復(fù)制參數(shù)</param>
        /// <param name="externalTransaction">執(zhí)行的事務(wù)對象</param>
        /// <returns>插入數(shù)量</returns>
        public static int BulkCopy<TModel>(this SqlConnection connection,
          IEnumerable<TModel> source,
          string tableName = null,
          int bulkCopyTimeout = 30,
          int batchSize = 0,
          SqlBulkCopyOptions options = SqlBulkCopyOptions.Default,
          SqlTransaction externalTransaction = null)
        {
          //創(chuàng)建讀取器
          using (var reader = new EnumerableReader<TModel>(source))
          {
            //創(chuàng)建批量插入對象
            using (var copy = new SqlBulkCopy(connection, options, externalTransaction))
            {
              //插入的表
              copy.DestinationTableName = tableName ?? typeof(TModel).Name;
              //寫入數(shù)據(jù)庫一批數(shù)量
              copy.BatchSize = batchSize;
              //超時時間
              copy.BulkCopyTimeout = bulkCopyTimeout;
              //創(chuàng)建字段映射【如果沒有此字段映射會導(dǎo)致數(shù)據(jù)填錯位置,如果類型不對還會導(dǎo)致報錯】【因為:沒有此字段映射默認(rèn)是按照列序號對應(yīng)插入的】
              foreach (var column in ModelToDataTable<TModel>.Columns)
              {
                //創(chuàng)建字段映射
                copy.ColumnMappings.Add(column.ColumnName, column.ColumnName);
              }
              //將數(shù)據(jù)批量寫入數(shù)據(jù)庫
              copy.WriteToServer(reader);
              //返回插入數(shù)據(jù)數(shù)量
              return reader.Depth;
            }
          }
        }

        /// <summary>
        /// 批量復(fù)制-異步
        /// </summary>
        /// <typeparam name="TModel">插入的模型對象</typeparam>
        /// <param name="source">需要批量插入的數(shù)據(jù)源</param>
        /// <param name="connection">數(shù)據(jù)庫連接對象</param>
        /// <param name="tableName">插入表名稱【為NULL默認(rèn)為實體名稱】</param>
        /// <param name="bulkCopyTimeout">插入超時時間</param>
        /// <param name="batchSize">寫入數(shù)據(jù)庫一批數(shù)量【如果為0代表全部一次性插入】最合適數(shù)量【這取決于您的環(huán)境,尤其是行數(shù)和網(wǎng)絡(luò)延遲。就個人而言,我將從BatchSize屬性設(shè)置為1000行開始,然后看看其性能如何。如果可行,那么我將使行數(shù)加倍(例如增加到2000、4000等),直到性能下降或超時。否則,如果超時發(fā)生在1000,那么我將行數(shù)減少一半(例如500),直到它起作用為止?!?lt;/param>
        /// <param name="options">批量復(fù)制參數(shù)</param>
        /// <param name="externalTransaction">執(zhí)行的事務(wù)對象</param>
        /// <returns>插入數(shù)量</returns>
        public static async Task<int> BulkCopyAsync<TModel>(this SqlConnection connection,
          IEnumerable<TModel> source,
          string tableName = null,
          int bulkCopyTimeout = 30,
          int batchSize = 0,
          SqlBulkCopyOptions options = SqlBulkCopyOptions.Default,
          SqlTransaction externalTransaction = null)
        {
          //創(chuàng)建讀取器
          using (var reader = new EnumerableReader<TModel>(source))
          {
            //創(chuàng)建批量插入對象
            using (var copy = new SqlBulkCopy(connection, options, externalTransaction))
            {
              //插入的表
              copy.DestinationTableName = tableName ?? typeof(TModel).Name;
              //寫入數(shù)據(jù)庫一批數(shù)量
              copy.BatchSize = batchSize;
              //超時時間
              copy.BulkCopyTimeout = bulkCopyTimeout;
              //創(chuàng)建字段映射【如果沒有此字段映射會導(dǎo)致數(shù)據(jù)填錯位置,如果類型不對還會導(dǎo)致報錯】【因為:沒有此字段映射默認(rèn)是按照列序號對應(yīng)插入的】
              foreach (var column in ModelToDataTable<TModel>.Columns)
              {
                //創(chuàng)建字段映射
                copy.ColumnMappings.Add(column.ColumnName, column.ColumnName);
              }
              //將數(shù)據(jù)批量寫入數(shù)據(jù)庫
              await copy.WriteToServerAsync(reader);
              //返回插入數(shù)據(jù)數(shù)量
              return reader.Depth;
            }
          }
        }
      }

    封裝的迭代器數(shù)據(jù)讀取器

     /// <summary>
      /// 迭代器數(shù)據(jù)讀取器
      /// </summary>
      /// <typeparam name="TModel">模型類型</typeparam>
      public class EnumerableReader<TModel> : IDataReader
      {
        /// <summary>
        /// 實例化迭代器讀取對象
        /// </summary>
        /// <param name="source">模型源</param>
        public EnumerableReader(IEnumerable<TModel> source)
        {
          _source = source ?? throw new ArgumentNullException(nameof(source));
          _enumerable = source.GetEnumerator();
        }

        private readonly IEnumerable<TModel> _source;
        private readonly IEnumerator<TModel> _enumerable;
        private object[] _currentDataRow = Array.Empty<object>();
        private int _depth;
        private bool _release;

        public void Dispose()
        {
          _release = true;
          _enumerable.Dispose();
        }

        public int GetValues(object[] values)
        {
          if (values == null) throw new ArgumentNullException(nameof(values));
          var length = Math.Min(_currentDataRow.Length, values.Length);
          Array.Copy(_currentDataRow, values, length);
          return length;
        }

        public int GetOrdinal(string name)
        {
          for (int i = 0; i < ModelToDataTable<TModel>.Columns.Count; i++)
          {
            if (ModelToDataTable<TModel>.Columns[i].ColumnName == name) return i;
          }

          return -1;
        }

        public long GetBytes(int ordinal, long dataIndex, byte[] buffer, int bufferIndex, int length)
        {
          if (dataIndex < 0) throw new Exception($"起始下標(biāo)不能小于0!");
          if (bufferIndex < 0) throw new Exception("目標(biāo)緩沖區(qū)起始下標(biāo)不能小于0!");
          if (length < 0) throw new Exception("讀取長度不能小于0!");
          var numArray = (byte[])GetValue(ordinal);
          if (buffer == null) return numArray.Length;
          if (buffer.Length <= bufferIndex) throw new Exception("目標(biāo)緩沖區(qū)起始下標(biāo)不能大于目標(biāo)緩沖區(qū)范圍!");
          var freeLength = Math.Min(numArray.Length - bufferIndex, length);
          if (freeLength <= 0) return 0;
          Array.Copy(numArray, dataIndex, buffer, bufferIndex, length);
          return freeLength;
        }

        public long GetChars(int ordinal, long dataIndex, char[] buffer, int bufferIndex, int length)
        {
          if (dataIndex < 0) throw new Exception($"起始下標(biāo)不能小于0!");
          if (bufferIndex < 0) throw new Exception("目標(biāo)緩沖區(qū)起始下標(biāo)不能小于0!");
          if (length < 0) throw new Exception("讀取長度不能小于0!");
          var numArray = (char[])GetValue(ordinal);
          if (buffer == null) return numArray.Length;
          if (buffer.Length <= bufferIndex) throw new Exception("目標(biāo)緩沖區(qū)起始下標(biāo)不能大于目標(biāo)緩沖區(qū)范圍!");
          var freeLength = Math.Min(numArray.Length - bufferIndex, length);
          if (freeLength <= 0) return 0;
          Array.Copy(numArray, dataIndex, buffer, bufferIndex, length);
          return freeLength;
        }

        public bool IsDBNull(int i)
        {
          var value = GetValue(i);
          return value == null || value is DBNull;
        }
        public bool NextResult()
        {
          //移動到下一個元素
          if (!_enumerable.MoveNext()) return false;
          //行層+1
          Interlocked.Increment(ref _depth);
          //得到數(shù)據(jù)行
          _currentDataRow = ModelToDataTable<TModel>.ToRowData.Invoke(_enumerable.Current);
          return true;
        }

        public byte GetByte(int i) => (byte)GetValue(i);
        public string GetName(int i) => ModelToDataTable<TModel>.Columns[i].ColumnName;
        public string GetDataTypeName(int i) => ModelToDataTable<TModel>.Columns[i].DataType.Name;
        public Type GetFieldType(int i) => ModelToDataTable<TModel>.Columns[i].DataType;
        public object GetValue(int i) => _currentDataRow[i];
        public bool GetBoolean(int i) => (bool)GetValue(i);
        public char GetChar(int i) => (char)GetValue(i);
        public Guid GetGuid(int i) => (Guid)GetValue(i);
        public short GetInt16(int i) => (short)GetValue(i);
        public int GetInt32(int i) => (int)GetValue(i);
        public long GetInt64(int i) => (long)GetValue(i);
        public float GetFloat(int i) => (float)GetValue(i);
        public double GetDouble(int i) => (double)GetValue(i);
        public string GetString(int i) => (string)GetValue(i);
        public decimal GetDecimal(int i) => (decimal)GetValue(i);
        public DateTime GetDateTime(int i) => (DateTime)GetValue(i);
        public IDataReader GetData(int i) => throw new NotSupportedException();
        public int FieldCount => ModelToDataTable<TModel>.Columns.Count;
        public object this[int i] => GetValue(i);
        public object this[string name] => GetValue(GetOrdinal(name));
        public void Close() => Dispose();
        public DataTable GetSchemaTable() => ModelToDataTable<TModel>.ToDataTable(_source);
        public bool Read() => NextResult();
        public int Depth => _depth;
        public bool IsClosed => _release;
        public int RecordsAffected => 0;
      }

    模型對象轉(zhuǎn)數(shù)據(jù)行工具類

    /// <summary>
      /// 對象轉(zhuǎn)換成DataTable轉(zhuǎn)換類
      /// </summary>
      /// <typeparam name="TModel">泛型類型</typeparam>
      public static class ModelToDataTable<TModel>
      {
        static ModelToDataTable()
        {
          //如果需要剔除某些列可以修改這段代碼
          var propertyList = typeof(TModel).GetProperties().Where(w => w.CanRead).ToArray();
          Columns = new ReadOnlyCollection<DataColumn>(propertyList
            .Select(pr => new DataColumn(pr.Name, GetDataType(pr.PropertyType))).ToArray());
          //生成對象轉(zhuǎn)數(shù)據(jù)行委托
          ToRowData = BuildToRowDataDelegation(typeof(TModel), propertyList);
        }

        /// <summary>
        /// 構(gòu)建轉(zhuǎn)換成數(shù)據(jù)行委托
        /// </summary>
        /// <param name="type">傳入類型</param>
        /// <param name="propertyList">轉(zhuǎn)換的屬性</param>
        /// <returns>轉(zhuǎn)換數(shù)據(jù)行委托</returns>
        private static Func<TModel, object[]> BuildToRowDataDelegation(Type type, PropertyInfo[] propertyList)
        {
          var source = Expression.Parameter(type);
          var items = propertyList.Select(property => ConvertBindPropertyToData(source, property));
          var array = Expression.NewArrayInit(typeof(object), items);
          var lambda = Expression.Lambda<Func<TModel, object[]>>(array, source);
          return lambda.Compile();
        }

        /// <summary>
        /// 將屬性轉(zhuǎn)換成數(shù)據(jù)
        /// </summary>
        /// <param name="source">源變量</param>
        /// <param name="property">屬性信息</param>
        /// <returns>獲取屬性數(shù)據(jù)表達(dá)式</returns>
        private static Expression ConvertBindPropertyToData(ParameterExpression source, PropertyInfo property)
        {
          var propertyType = property.PropertyType;
          var expression = (Expression)Expression.Property(source, property);
          if (propertyType.IsEnum)
            expression = Expression.Convert(expression, propertyType.GetEnumUnderlyingType());
          return Expression.Convert(expression, typeof(object));
        }

        /// <summary>
        /// 獲取數(shù)據(jù)類型
        /// </summary>
        /// <param name="type">屬性類型</param>
        /// <returns>數(shù)據(jù)類型</returns>
        private static Type GetDataType(Type type)
        {
          //枚舉默認(rèn)轉(zhuǎn)換成對應(yīng)的值類型
          if (type.IsEnum)
            return type.GetEnumUnderlyingType();
          //可空類型
          if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
            return GetDataType(type.GetGenericArguments().First());
          return type;
        }

        /// <summary>
        /// 列集合
        /// </summary>
        public static IReadOnlyList<DataColumn> Columns { get; }

        /// <summary>
        /// 對象轉(zhuǎn)數(shù)據(jù)行委托
        /// </summary>
        public static Func<TModel, object[]> ToRowData { get; }

        /// <summary>
        /// 集合轉(zhuǎn)換成DataTable
        /// </summary>
        /// <param name="source">集合</param>
        /// <param name="tableName">表名稱</param>
        /// <returns>轉(zhuǎn)換完成的DataTable</returns>
        public static DataTable ToDataTable(IEnumerable<TModel> source, string tableName = "TempTable")
        {
          //創(chuàng)建表對象
          var table = new DataTable(tableName);
          //設(shè)置列
          foreach (var dataColumn in Columns)
          {
            table.Columns.Add(new DataColumn(dataColumn.ColumnName, dataColumn.DataType));
          }

          //循環(huán)轉(zhuǎn)換每一行數(shù)據(jù)
          foreach (var item in source)
          {
            table.Rows.Add(ToRowData.Invoke(item));
          }

          //返回表對象
          return table;
        }
      }

    三、測試封裝代碼

    1.測試代碼

    創(chuàng)表代碼

    CREATE TABLE [dbo].[Person](
     [Id] [BIGINT] NOT NULL,
     [Name] [VARCHAR](64) NOT NULL,
     [Age] [INT] NOT NULL,
     [CreateTime] [DATETIME] NULL,
     [Sex] [INT] NOT NULL,
    PRIMARY KEY CLUSTERED
    (
     [Id] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
    ) ON [PRIMARY]

    實體類代碼

    定義的實體的屬性名稱需要和SqlServer列名稱類型對應(yīng)

    public class Person
    {
      public long Id { get; set; }
      public string Name { get; set; }
      public int Age { get; set; }
      public DateTime? CreateTime { get; set; }
      public Gender Sex { get; set; }
    }

    public enum Gender
    {
      Man = 0,
      Woman = 1
    }

    測試方法

    //生成10萬條數(shù)據(jù)
    var persons = new Person[100000];
    var random = new Random();
    for (int i = 0; i < persons.Length; i++)
    {
      persons[i] = new Person
      {
        Id = i + 1,
        Name = "張三" + i,
        Age = random.Next(1, 128),
        Sex = (Gender)random.Next(2),
        CreateTime = random.Next(2) == 0 ? null : (DateTime?) DateTime.Now.AddSeconds(i)
      };
    }

    //創(chuàng)建數(shù)據(jù)庫連接
    using (var conn = new SqlConnection("Server=.;Database=DemoDataBase;User ID=sa;Password=8888;"))
    {
      conn.Open();
      var sw = Stopwatch.StartNew();
      //批量插入數(shù)據(jù)
      var qty = conn.BulkCopy(persons);
      sw.Stop();
      Console.WriteLine(sw.Elapsed.TotalMilliseconds + "ms");
    }

    執(zhí)行批量插入結(jié)果

    226.4767ms

    請按任意鍵繼續(xù). . .

    四、代碼下載

    GitHub代碼地址:https://github.com/liu-zhen-liang/PackagingComponentsSet/tree/main/SqlBulkCopyComponents

    來源:腳本之家

    鏈接:https://www.jb51.net/article/201634.htm

    申請創(chuàng)業(yè)報道,分享創(chuàng)業(yè)好點子。點擊此處,共同探討創(chuàng)業(yè)新機(jī)遇!

    相關(guān)標(biāo)簽
    sqlserver

    相關(guān)文章

    熱門排行

    信息推薦