2016-08-18 35 views
2

我有一个关于存储过程以用户定义的表类型作为参数的问题。我知道我只需要在与SQL DB中的用户定义表类型相对应的c#代码中创建一个DataTable。就像这里 How to pass User Defined Table Type as Stored Procedured parameter in C#C#自动生成SQL“用户定义的表类型”

但是,我想避免的是在代码中手动创建DataTable,而是自动创建DataTable。是否有可能通过查询从数据库中获取?

如果这是不可能的,那么另一种可能性是获得用户定义表类型的定义,然后使用它自动生成DataTable。但是接下来的问题是如何获得类型的定义?

任何人都可以解决这个问题,我发现的所有例子都是在代码中手动生成用户定义的数据类型作为DataTable。

回答

2

如果你知道表类型的名称,你应该能够执行下面这段SQL的:

declare @a dbo.TT 
select * from @a 

(其中dbo.TT是表类型的名称)

这将生成一个包含所有适当模式信息(列名和类型)的空结果集。如果您使用DataAdapter来填充DataTable,则应该全部设置。

+0

谢谢,正是我所寻找的,因为有不同数量的列的多种类型。它自动处理。 –

0

试试这个(这仅适用于发送一个存储过程值一列的数据集是很有用的。)

public void AddSQLTableParm<T>(string parmName, 
     IEnumerable<T> values, 
     string typeName = "dbo.keyIds") // <== here put SQL Server UDT Type neame 
    { 
     var parm = new SqlParameter(parmName, 
          DbParamList.CreateDataTable(values)) 
     { 
      SqlDbType = SqlDbType.Structured, 
      TypeName = typeName 
     }; 
     Add(parmName, parm); 
    } 

如果你想多列数据集(SQL Server中的多列UDT)你将不得不延长本,签名将成为:

三列数据集:

public void AddSQLTableParm<T1, T2, T3>(
     string parmName, string typeName = "dbo.keyIds", 
     IEnumerable<T1> value1s, 
     IEnumerable<T1> value2s, 
     IEnumerable<T1> value3s) 
{ .... } 

dbParamList定义:

public class DbParamList : List<IDbDataParameter> 
{ 
    private DbParamList() {} 
    public static DbParamList Make(IEnumerable<SqlParameter> parms) 
    { 
     var prmLst = new DbParamList(); 
     prmLst.AddRange(parms); 
     return prmLst; 
    } 

    public static DbParamList Make(params SqlParameter[] parms) 
    { 
     var prmLst = new DbParamList(); 
     prmLst.AddRange(parms); 
     return prmLst; 
    } 

    public void AddSQLParm(string parmName, bool value) 
    { Add(new SqlParameter(parmName, value ? "1" : "0")); } 

    public void AddSQLParm(string parmName, bool? value) 
    { 
     if (!value.HasValue) 
     { 
      throw new ArgumentNullException(
       "Null value passed to AddSQLParm<>()"); 
     } 
     Add(new SqlParameter(parmName, value.Value ? "1" : "0")); 
    } 

    public void AddSQLParm<T>(string parmName, T value) 
    { 
     var type = typeof(T); 
     if (type.IsEnum) Add(new SqlParameter(parmName, 
      Convert.ChangeType(value, Enum.GetUnderlyingType(type)))); 

     else Add(new SqlParameter(parmName, value)); 
    } 

    public void AddSQLParm<T>(string parmName, T? value, 
     bool ignoreNull = false) where T : struct 
    { 
     var type = typeof(T); 

     if (!value.HasValue) 
     { 
      if (ignoreNull) return; 
      throw new ArgumentNullException(
       "Null value passed to AddSQLParm<>()"); 
     } 
     // --------------------------------------- 

     if (type.IsEnum) Add(new SqlParameter(parmName, 
      Convert.ChangeType(value.Value, Enum.GetUnderlyingType(type)))); 
     else Add(new SqlParameter(parmName, value.Value)); 
    } 

    public void AddSQLTableParm<T>(string parmName, IEnumerable<T> values) 
    { 
     var parm = new SqlParameter(parmName, CreateDataTable(values)) 
     { 
      SqlDbType = SqlDbType.Structured, 
      TypeName = "dbo.keyIds" 
     }; 
     Add(parm); 
    } 

    internal static DataTable CreateDataTable<T>(IEnumerable<T> values) 
    { 
     var dt = new DataTable(); 
     var props = typeof (T).GetProperties(); 
     if (props.Length > 0) 
     { 
      foreach (var col in props) 
       dt.Columns.Add(col.Name, col.PropertyType); 
      foreach (var id in values) 
      { 
       var newRow = dt.NewRow(); 
       foreach (var prop in id.GetType().GetProperties()) 
        newRow[prop.Name] = prop.GetValue(id, null); 
       dt.Rows.Add(newRow); 
      } 
     } 
     else 
     { 
      dt.Columns.Add("ids"); 
      foreach (var id in values) dt.Rows.Add(id); 
     } 
     return dt; 
    } 

} 
+0

刚才有看过上面的,看起来像一个可用的解决方案。为了这个可用,值需要有正确的类型,是否正确? –

+0

没错,这就是为什么它的泛型,类型参数T是你如何告诉它的类型。但是,这仅适用于发送存储过程的一列值的数据集。如果您需要多列数据集(SQL Server中的多列UDT),则必须对此进行扩展。 –