I know the method below isn't meant to work with any Entity, and its use shouldn't be enforced.
I found a System.Data.Linq.Table extension method which uses SqlBulkCopy to insert data. I am trying to adapt it to the Entity Framework but it throws a strange exception, while the original works for Linq-To-Sql data classes. I couldn't find the flaw so far, it happens with any SQL table, in a 1-1 mapping. Could you help me?
public static class ObjectQueryExtensions
{
public static string GetName<TEntity>(
this ObjectQuery<TEntity> objectQuery)
where TEntity : class
{
var tableNameGroup = new Regex(@"FROM\s([^\s]*)\s"
, RegexOptions.IgnoreCase);
var sql = objectQuery.ToTraceString();
var tableNameGroupMatch = tableNameGroup.Match(sql);
return tableNameGroupMatch.Groups[1].Value;
}
public static void BulkInsert<TEntity>(
this ObjectQuery<TEntity> objectQuery
, IEnumerable<TEntity> items)
where TEntity : class
{
using (var dt = new DataTable())
{
var properties = typeof(TEntity)
.GetProperties()
.Where(property => property.Name != "EntityKey")
.Where(property => property.Name != "EntityState")
;
foreach (var property in properties)
{
dt.Columns.Add(property.Name
, Nullable.GetUnderlyingType(property.PropertyType)
?? property.PropertyType);
}
foreach (var t in items)
{
DataRow row = dt.NewRow();
foreach (var info in properties)
{
row[info.Name] = info.GetValue(t, null) ?? DBNull.Value;
}
dt.Rows.Add(row);
}
var entityConnection = (EntityConnection)objectQuery
.Context.Connection;
using (var sqlBulkCopy = new SqlBulkCopy(
entityConnection.StoreConnection.ConnectionString))
{
sqlBulkCopy.DestinationTableName = objectQuery.GetName();
sqlBulkCopy.WriteToServer(dt);
}
}
}
}
The exception
Test method LinqExtensionsTest.ObjectQueryExtensionsTest.BulkInsertTest threw exception: System.InvalidOperationException: The given value of type Int64 from the data source cannot be converted to type datetime of the specified target column. ---> System.InvalidCastException: Failed to convert parameter value from a Int64 to a DateTime. ---> System.InvalidCastException: Invalid cast from 'Int64' to 'DateTime'..
The stack trace
System.Int64.System.IConvertible.ToDateTime(IFormatProvider provider) System.Convert.ChangeType(Object value, Type conversionType, IFormatProvider provider) System.Data.SqlClient.SqlParameter.CoerceValue(Object value, MetaType destinationType) System.Data.SqlClient.SqlParameter.CoerceValue(Object value, MetaType destinationType) System.Data.SqlClient.SqlBulkCopy.ConvertValue(Object value, _SqlMetaData metadata) System.Data.SqlClient.SqlBulkCopy.ConvertValue(Object value, _SqlMetaData metadata) System.Data.SqlClient.SqlBulkCopy.WriteToServerInternal() System.Data.SqlClient.SqlBulkCopy.WriteRowSourceToServer(Int32 columnCount) System.Data.SqlClient.SqlBulkCopy.WriteToServer(DataTable table, DataRowState rowState) System.Data.SqlClient.SqlBulkCopy.WriteToServer(DataTable table) LinqExtensions.ObjectQueryExtensions.BulkInsert[TEntity](ObjectQuery
1 objectQuery, IEnumerable
1 items) in LinqExtensions\LinqExtensions\ObjectQueryExtensions.cs: line 60 LinqExtensionsTest.ObjectQueryExtensionsTest.BulkInsertTest() in LinqExtensions\LinqExtensionsTest\ObjectQueryExtensionsTest.cs: line 88