对DataTable进行子类化

时间:2015-05-11 13:28:18

标签: c# entity-framework sql-server-2012

我使用实体框架和一个采用表值参数(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()

2 个答案:

答案 0 :(得分:2)

尝试将参数更改为:

{{1}}

答案 1 :(得分:1)

另一种选择是创建一个DataTable工厂而不是创建一个新类型,该工厂可以创建具有正确列的数据表。