c#
Using DataTable as a Table Valued Parameter in EF Core 2.0
[Updated problem description] We have a bulk import process for which we were passing IEnumerable<SqlDataRecord> as a Table Valued Parameter (TVP) to a Stored Proc, as DataTable Type was not available until EF Core 1.1. We just upgraded our project to use .Net Core 2.0 and started updating the code to use DataTable. The ExecuteSqlCommandAsync command started throwing an InvalidCastException. Here are the exception details: System.InvalidCastException occurred HResult=0x80004002 Message=Failed to convert parameter value from a DataTable to a IEnumerable`1. Source=<Cannot evaluate the exception source> StackTrace: at System.Data.SqlClient.SqlParameter.CoerceValue(Object value, MetaType destinationType, Boolean& coercedToDataFeed, Boolean& typeChanged, Boolean allowStreaming) at System.Data.SqlClient.SqlParameter.GetCoercedValue() at System.Data.SqlClient.SqlParameter.Validate(Int32 index, Boolean isCommandProc) at System.Data.SqlClient.SqlCommand.BuildParamList(TdsParser parser, SqlParameterCollection parameters) at System.Data.SqlClient.SqlCommand.BuildExecuteSql(CommandBehavior behavior, String commandText, SqlParameterCollection parameters, _SqlRPC& rpc) at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, SqlDataReader ds) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean asyncWrite, String method) at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion, Boolean sendToPipe, Int32 timeout, Boolean asyncWrite, String methodName) at System.Data.SqlClient.SqlCommand.BeginExecuteNonQuery(AsyncCallback callback, Object stateObject) at System.Threading.Tasks.TaskFactory`1.FromAsyncImpl(Func`3 beginMethod, Func`2 endFunction, Action`1 endAction, Object state, TaskCreationOptions creationOptions) at System.Threading.Tasks.TaskFactory`1.FromAsync(Func`3 beginMethod, Func`2 endMethod, Object state) at System.Data.SqlClient.SqlCommand.ExecuteNonQueryAsync(CancellationToken cancellationToken) at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.<ExecuteAsync>d__26.MoveNext() at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() at Microsoft.EntityFrameworkCore.RelationalDatabaseFacadeExtensions.<ExecuteSqlCommandAsync>d__11.MoveNext() at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() at X.Y.Repositories.Repository.<Import>d__4.MoveNext() in Repository.cs:line 95 at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at X.Y.Services.ImportService`2.<BulkImportAsync>d__6.MoveNext() in ImportService.cs:line 70 Inner Exception 1: InvalidCastException: Object must implement IConvertible. This is how I am calling the stored proc: var dataTable = new DataTable(); dataTable.Columns.Add("Col1", typeof(String)); dataTable.Columns.Add("Col2", typeof(String)); //and so on foreach (var record in records) { var row = dataTable.NewRow(); SetStringValue(row, "Col1", record.Field1); //SetStringValue is just a helper method that assigns DBNull.Value if the field value is null. SetStringValue(row, "Col2", record.Field2); //and so on dataTable.Rows.Add(row); } var param = new SqlParameter("#Records", dataTable) { TypeName = "TVPRecords", SqlDbType = SqlDbType.Structured }; await _dbContext.Database.ExecuteSqlCommandAsync("EXEC dbo.ImportData #Records", param); With DataTable now available in EF Core 2.0, I still can't use it to pass as a TVP to a Stored Proc. Is it because its not supported yet or may be a bug?
Related Links
Using implicit typing [duplicate]
Pass a .sql file to SQL Server for execution
JSON deserialize with nested list in C#
Unit testing chained private methods in C#
Invoking WPF Dispatcher with anonymous method
How to make this code DRY?
ManagementScope and Win32_Product retrieving executable paths
Response.Redirect from one web project to another in Visual Studio
Insert rows into Access Table in order from c#
Host TCP Chat Server in IIS
hooks in function argument to accommodate future data?
Change datetime to date in MVC 3 C#
Default state of the systray icon
Help in understanding project euler's question #54
XtraGrid Questions
Add table dynamically in Entity framework in MVC