c# - 子类化数据表

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

我正在使用 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/

相关文章:

c# - Entity Framework Core 原始 SQL 错误 : System. ArgumentException 已添加具有相同键的项目。关键:身份证

c# - 如何使用身份列表从 Entity Framework 获取 ObjectResult

SQL Server 2012 - 根据另一列的值重置运行总计

用于计算 mtd、ytd 值的 SQL 查询

c# - 内部类放在哪里?

c# - 让 .net 应用程序和 vb6 应用程序互相交谈?

c# - 每次调用新方法时触发事件

entity-framework - Entity Framework 代码优先缓存

c# - 将 .net 4.0 中的 Entity Framework 与 Oracle 数据库一起使用 - 可能吗?

sql - sql中的sumProduct