如何从集合中创建DataTable以将其用作SQL表参数?

时间:2014-03-01 02:58:00

标签: c# .net generics reflection datatable

即使关闭验证,我也会在使用Entity Framework将大量数据插入SQL时出现性能问题。

我在网上看到,使用table参数将DataTable插入存储过程非常快,但我不想编写这种类型的代码来安排插入DataTable:

var table = new DataTable();
table.Columns.Add("Id");
table.Columns.Add("Store");
table.Columns.Add("Name");
table.Columns.Add("Amount");
table.Columns.Add("Active");
table.Columns.Add("Status");

foreach (var s in model.Sales)
{
    var row = table.NewRow();
    row["Id"] = l.Id;
    row["Store"] = (int)l.Store;
    row["Name"] = l.Name;
    row["Amount"] = l.Amount;
    row["Active"] = true;
    row["Status"] = string.IsNullOrEmpty(l.Status) ? null : l.Status;
    table.Rows.Add(row);
}

var parameter = new SqlParameter("Table", SqlDbType.Structured)
    {
        Value = table,
        TypeName = "SqlDefinedTableType"
    };

如何从集合中创建DataTable并将其用作SQL表参数?

1 个答案:

答案 0 :(得分:2)

您可以使用泛型来解决这些问题。这是一个将类型集合转换为DataTable的方法:

public static DataTable CreateDataTable<T>(ICollection<T> values)
{
    var table = new DataTable();

    // Get the generic type from the collection
    var type = values.GetType().GetGenericArguments()[0];

    // Add columns base on the type's properties
    foreach (var property in type.GetProperties())
    {
        /* It is necessary to evaluate whether each property is nullable or not.
         * This is because DataTables only support null values in the form of
         * DBNull.Value.
         */
        var propertyType = property.PropertyType;
        var computedType =
            // If the type is nullable
            propertyType.IsGenericType
                && propertyType.GetGenericTypeDefinition() == typeof(Nullable<>) 
            // Get its underlying type
            ? propertyType.GetGenericArguments()[0]
            // If it isn't, get return the property type.
            : propertyType;

        table.Columns.Add(new DataColumn(property.Name, computedType));
    }

    // Add rows into the DataTable based off of the values
    foreach (var value in values)
    {
        var row = table.NewRow();
        foreach (var property in value.GetType().GetProperties())
        {
            // Create a container to hold the data in the value
            object data = null;
            // If the property we are adding exists...
            if (row.Table.Columns.Contains(property.Name))
                // Then get the value of that property
                data = value.GetType().GetProperty(property.Name).GetValue(value, null);

            // If the value is null, convert the value to DBNull
            row[property.Name] = data ?? DBNull.Value;
        }
        table.Rows.Add(row);
    }

    return table;
}

然后,您可以使用上述函数返回的DataTable创建SqlParameter并将其传递给您选择的SqlCommand

var parameter = new SqlParameter("Table", SqlDbType.Structured)
    {
        Value = CreateDataTable(model.Sales),
        TypeName = "SqlDefinedTableType"
    };

修改:我在原始答案中编辑了该函数以支持可空类型。