C#auto生成SQL"用户定义的表类型"

时间:2016-08-18 14:33:24

标签: c# sql datatable

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

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

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

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

2 个答案:

答案 0 :(得分:5)

如果您知道表类型的名称,则应该能够执行以下SQL:

declare @a dbo.TT
select * from @a

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

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

答案 1 :(得分: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;
    }

}