Skip to content

Instantly share code, notes, and snippets.

@aliozgur
Created March 28, 2018 08:12
Show Gist options
  • Save aliozgur/3e25d3dc5f0cb9696f8ee295d06a8ab8 to your computer and use it in GitHub Desktop.
Save aliozgur/3e25d3dc5f0cb9696f8ee295d06a8ab8 to your computer and use it in GitHub Desktop.
SqlBulk Insert with SqlBulkCopy
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;
namespace Your.Prefereed.Name
{
/// <summary>
/// Use for an alternative param name other than the propery name
/// </summary>
[System.AttributeUsage(AttributeTargets.Property)]
public class BulkInsertParamNameAttribute : Attribute
{
public string Name { get; set; }
public BulkInsertParamNameAttribute(string name)
{
Name = name;
}
}
/// <summary>
/// Ignore this property
/// </summary>
[System.AttributeUsage(AttributeTargets.Property)]
public class BulkInsertIgnoreAttribute : Attribute
{
}
public class BulkInsert
{
public static void Save<T>(IDbConnection conn, string tableName, List<T> items) where T :class
{
var properties = DiscoverTypeProperties(typeof(T));
using (var reader = items.GetDataReader())
{
var destTableName = tableName;
using (SqlBulkCopy copy = new SqlBulkCopy(conn.ConnectionString))
{
copy.BatchSize = 15000;
copy.DestinationTableName = destTableName;
copy.NotifyAfter = 0;
foreach (var i in Enumerable.Range(0, properties.Count))
{
copy.ColumnMappings.Add(i, properties[i]);
}
copy.WriteToServer(reader);
copy.Close();
}
}
}
private static List<string> DiscoverTypeProperties(Type t)
{
var result = new List<string>();
var props = (
from p in t.GetProperties()
let nameAttr = p.GetCustomAttributes(typeof(BulkInsertParamNameAttribute), true)
let ignoreAttr = p.GetCustomAttributes(typeof(BulkInsertIgnoreAttribute), true)
select new { Property = p, Names = nameAttr, Ignore = ignoreAttr }).ToList();
props.ForEach(p =>
{
if (p.Ignore != null && p.Ignore.Length > 0)
return;
var pName = p.Names.FirstOrDefault() as BulkInsertParamNameAttribute;
if (pName != null && !String.IsNullOrWhiteSpace(pName.Name))
result.Add(pName.Name);
else
result.Add(p.Property.Name);
});
return result;
}
}
}
using System;
using System.Collections.Generic;
using System.Data;
using System.Reflection;
namespace Your.Preferred.Name
{
public static class GenericListDataReaderExtensions
{
public static ListDataReader<T> GetDataReader<T>(this IEnumerable<T> list)
{
return new ListDataReader<T>(list);
}
}
public class ListDataReader<T> : IDataReader
{
private IEnumerator<T> list = null;
private List<PropertyInfo> properties = new List<PropertyInfo>();
private Dictionary<string, int> nameLookup = new Dictionary<string, int>();
public ListDataReader(IEnumerable<T> list)
{
this.list = list.GetEnumerator();
properties.AddRange(
typeof(T)
.GetProperties(
BindingFlags.GetProperty |
BindingFlags.Instance |
BindingFlags.Public |
BindingFlags.DeclaredOnly
));
for (int i = 0; i < properties.Count; i++)
{
nameLookup[properties[i].Name] = i;
}
}
#region IDataReader Members
public void Close()
{
list.Dispose();
}
public int Depth
{
get { throw new NotImplementedException(); }
}
public DataTable GetSchemaTable()
{
throw new NotImplementedException();
}
public bool IsClosed
{
get { throw new NotImplementedException(); }
}
public bool NextResult()
{
throw new NotImplementedException();
}
public bool Read()
{
return list.MoveNext();
}
public int RecordsAffected
{
get { throw new NotImplementedException(); }
}
#endregion
#region IDisposable Members
public void Dispose()
{
Close();
}
#endregion
#region IDataRecord Members
public int FieldCount
{
get { return properties.Count; }
}
public bool GetBoolean(int i)
{
return (bool)GetValue(i);
}
public byte GetByte(int i)
{
return (byte)GetValue(i);
}
public long GetBytes(int i, long fieldOffset, byte[] buffer, int bufferoffset, int length)
{
throw new NotImplementedException();
}
public char GetChar(int i)
{
return (char)GetValue(i);
}
public long GetChars(int i, long fieldoffset, char[] buffer, int bufferoffset, int length)
{
throw new NotImplementedException();
}
public IDataReader GetData(int i)
{
throw new NotImplementedException();
}
public string GetDataTypeName(int i)
{
throw new NotImplementedException();
}
public DateTime GetDateTime(int i)
{
return (DateTime)GetValue(i);
}
public decimal GetDecimal(int i)
{
return (decimal)GetValue(i);
}
public double GetDouble(int i)
{
return (double)GetValue(i);
}
public Type GetFieldType(int i)
{
return properties[i].PropertyType;
}
public float GetFloat(int i)
{
return (float)GetValue(i);
}
public Guid GetGuid(int i)
{
return (Guid)GetValue(i);
}
public short GetInt16(int i)
{
return (short)GetValue(i);
}
public int GetInt32(int i)
{
return (int)GetValue(i);
}
public long GetInt64(int i)
{
return (long)GetValue(i);
}
public string GetName(int i)
{
return properties[i].Name;
}
public int GetOrdinal(string name)
{
if (nameLookup.ContainsKey(name))
{
return nameLookup[name];
}
else
{
return -1;
}
}
public string GetString(int i)
{
return (string)GetValue(i);
}
public object GetValue(int i)
{
return properties[i].GetValue(list.Current, null);
}
public int GetValues(object[] values)
{
int getValues = Math.Max(FieldCount, values.Length);
for (int i = 0; i < getValues; i++)
{
values[i] = GetValue(i);
}
return getValues;
}
public bool IsDBNull(int i)
{
return GetValue(i) == null;
}
public object this[string name]
{
get
{
return GetValue(GetOrdinal(name));
}
}
public object this[int i]
{
get
{
return GetValue(i);
}
}
#endregion
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment