我正在使用 Entity Framework 和一个采用表值参数 (TVP) 的存储过程。为此,我需要创建一个 DataTable
并像这样填充它:
var i = new DataTable();
i.Columns.Add("Type", typeof(byte));
i.Columns.Add("Code", typeof(int));
i.Rows.Add(0, 0);
i.Rows.Add(2, 31);
i.Rows.Add(4, 3121);
i.Rows.Add(4, 3111);
然后我可以将它作为参数传递给调用 SqlQuery
var result = ctx.Database.SqlQuery<MyResult>("select * from myStoredProc(@i)",
new SqlParameter("@i",i) { TypeName = "MyTVP" });
现在为了简化这一点,尤其是每次都重新创建列,我想我可以将 DataTable
子类化,如下所示:
public class MyTVP : DataTable
{
public MyTVP()
: base()
{
Columns.Add("Type", typeof(byte));
Columns.Add("Code", typeof(int));
}
}
所以现在我创建和填充表格的代码是这样的:
var i = new MyTVP();
i.Rows.Add(0, 0);
i.Rows.Add(2, 31);
i.Rows.Add(4, 3121);
i.Rows.Add(4, 3111);
但是如果我尝试将其作为参数传递给存储过程,我会得到一个 ArgumentException
:
No mapping exists from object type MyTVP to a known managed provider native type.
有没有一种方法可以将 DataTable
子类化,以便将其传递给存储过程?
我通过让 MyTVP
包装一个 DataTable
来解决这个问题,然后有一个公开 DataTable
的属性,但这有点凌乱。
堆栈跟踪:
at System.Data.SqlClient.MetaType.GetMetaTypeFromValue(Type dataType, Object value, Boolean inferLen, Boolean streamAllowed)
at System.Data.SqlClient.SqlParameter.GetMetaTypeOnly()
at System.Data.SqlClient.SqlParameter.get_DbType()
at System.Data.Entity.Infrastructure.Interception.DatabaseLogFormatter.LogParameter[TResult](DbCommand command, DbCommandInterceptionContext`1 interceptionContext, DbParameter parameter)
at System.Data.Entity.Infrastructure.Interception.DatabaseLogFormatter.LogCommand[TResult](DbCommand command, DbCommandInterceptionContext`1 interceptionContext)
at System.Data.Entity.Infrastructure.Interception.DatabaseLogFormatter.Executing[TResult](DbCommand command, DbCommandInterceptionContext`1 interceptionContext)
at System.Data.Entity.Infrastructure.Interception.DatabaseLogFormatter.ReaderExecuting(DbCommand command, DbCommandInterceptionContext`1 interceptionContext)
at System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.<Reader>b__d(IDbCommandInterceptor i, DbCommand t, DbCommandInterceptionContext`1 c)
at System.Data.Entity.Infrastructure.Interception.InternalDispatcher`1.Dispatch[TTarget,TInterceptionContext,TResult](TTarget target, Func`3 operation, TInterceptionContext interceptionContext, Action`3 executing, Action`3 executed)
at System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.Reader(DbCommand command, DbCommandInterceptionContext interceptionContext)
at System.Data.Entity.Internal.InterceptableDbCommand.ExecuteDbDataReader(CommandBehavior behavior)
at System.Data.Common.DbCommand.ExecuteReader(CommandBehavior behavior)
at System.Data.Entity.Core.Objects.ObjectContext.ExecuteStoreQueryInternal[TElement](String commandText, String entitySetName, ExecutionOptions executionOptions, Object[] parameters)
at System.Data.Entity.Core.Objects.ObjectContext.<>c__DisplayClass65`1.<ExecuteStoreQueryReliably>b__64()
at System.Data.Entity.Core.Objects.ObjectContext.ExecuteInTransaction[T](Func`1 func, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction, Boolean releaseConnectionOnSuccess)
at System.Data.Entity.Core.Objects.ObjectContext.<>c__DisplayClass65`1.<ExecuteStoreQueryReliably>b__63()
at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute[TResult](Func`1 operation)
at System.Data.Entity.Core.Objects.ObjectContext.ExecuteStoreQueryReliably[TElement](String commandText, String entitySetName, ExecutionOptions executionOptions, Object[] parameters)
at System.Data.Entity.Core.Objects.ObjectContext.ExecuteStoreQuery[TElement](String commandText, ExecutionOptions executionOptions, Object[] parameters)
at System.Data.Entity.Internal.InternalContext.<>c__DisplayClass14`1.<ExecuteSqlQuery>b__13()
at System.Data.Entity.Internal.LazyEnumerator`1.MoveNext()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at ConsoleApplication2.Program.Main(String[] args) in c:\Users\matt.burland\Documents\Visual Studio 2013\Projects\ConsoleApplication2\ConsoleApplication2\Program.cs:line 72
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
最佳答案
尝试将参数更改为:
new SqlParameter("@i", i) { TypeName = "MyTVP", SqlDbType = SqlDbType.Structured }
关于c# - 子类化数据表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30168970/