我使用实体框架和一个采用表值参数(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()
答案 0 :(得分:2)
尝试将参数更改为:
{{1}}
答案 1 :(得分:1)
另一种选择是创建一个DataTable工厂而不是创建一个新类型,该工厂可以创建具有正确列的数据表。