Reputation: 90475
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
Upvotes: 1
Views: 3970
Reputation: 63
I know that you created your DataTable from your entities, but my suggestion is to check if the order of the columns in the DataTable is the same of the columns in the table (maybe you changed your database and didn't update your model). If it is not the same you might have mismatching data type and bump into the invalid cast error. It happened to me ;)
Upvotes: 3
Reputation: 50273
The exception you got says pretty much it all: in your entity object you have a property of type Int64
which is defined as DateTime
in the database, and there is no way to implicitly convertfrom one to another. Do you really intend to represent that database column as an integer? Maybe it is just a mistake in the definition of the entity class.
Upvotes: 0