C# 从DataTable以编程方式创建SQL Server CE表
有人知道在运行时基于C# 从DataTable以编程方式创建SQL Server CE表,c#,.net,sql-server,sql-server-ce,C#,.net,Sql Server,Sql Server Ce,有人知道在运行时基于DataTable的模式创建SQL Server CE(Compact 3.5)表的最佳方法吗?我不想基于所有不同的可能数据类型等,制定一个createtable语句 作为奖励,您知道如何直接从数据表中填充它吗?我编写了一个合理的解决方案,但希望避免SQL类型的case语句: 首先是一个从.NET类型转换为SqlDBType的巧妙技巧: /// <summary> /// Gets the correct SqlDBType for a given .NET ty
DataTable
的模式创建SQL Server CE(Compact 3.5)表的最佳方法吗?我不想基于所有不同的可能数据类型等,制定一个createtable
语句
作为奖励,您知道如何直接从数据表中填充它吗?我编写了一个合理的解决方案,但希望避免SQL类型的case语句: 首先是一个从.NET类型转换为SqlDBType的巧妙技巧:
/// <summary>
/// Gets the correct SqlDBType for a given .NET type. Useful for working with SQL CE.
/// </summary>
/// <param name="type">The .Net Type used to find the SqlDBType.</param>
/// <returns>The correct SqlDbType for the .Net type passed in.</returns>
public static SqlDbType GetSqlDBTypeFromType(Type type)
{
TypeConverter tc = TypeDescriptor.GetConverter(typeof(DbType));
if (/*tc.CanConvertFrom(type)*/ true)
{
DbType dbType = (DbType)tc.ConvertFrom(type.Name);
// A cheat, but the parameter class knows how to map between DbType and SqlDBType.
SqlParameter param = new SqlParameter();
param.DbType = dbType;
return param.SqlDbType; // The parameter class did the conversion for us!!
}
else
{
throw new Exception("Cannot get SqlDbType from: " + type.Name);
}
}
//
///获取给定.NET类型的正确SqlDBType。对于使用SQLCE非常有用。
///
///用于查找SqlDBType的.Net类型。
///传入的.Net类型的正确SqlDbType。
公共静态SqlDbType GetSqlDBTypeFromType(类型类型)
{
TypeConverter tc=TypeDescriptor.GetConverter(typeof(DbType));
if(/*tc.CanConvertFrom(type)*/true)
{
DbType DbType=(DbType)tc.ConvertFrom(type.Name);
//一个欺骗,但是参数类知道如何在DbType和SqlDBType之间映射。
SqlParameter param=新的SqlParameter();
param.DbType=DbType;
return param.SqlDbType;//参数类为我们做了转换!!
}
其他的
{
抛出新异常(“无法从:“+type.Name”获取SqlDbType);
}
}
SQL语句中使用的类型的case语句:
/// <summary>
/// The method gets the SQL CE type name for use in SQL Statements such as CREATE TABLE
/// </summary>
/// <param name="dbType">The SqlDbType to get the type name for</param>
/// <param name="size">The size where applicable e.g. to create a nchar(n) type where n is the size passed in.</param>
/// <returns>The SQL CE compatible type for use in SQL Statements</returns>
public static string GetSqlServerCETypeName(SqlDbType dbType, int size)
{
// Conversions according to: http://msdn.microsoft.com/en-us/library/ms173018.aspx
bool max = (size == int.MaxValue) ? true : false;
bool over4k = (size > 4000) ? true : false;
switch (dbType)
{
case SqlDbType.BigInt:
return "bigint";
case SqlDbType.Binary:
return string.Format("binary ({0})", size);
case SqlDbType.Bit:
return "bit";
case SqlDbType.Char:
if (over4k) return "ntext";
else return string.Format("nchar({0})", size);
ETC...
//
///该方法获取SQL语句(如CREATE TABLE)中使用的SQL CE类型名称
///
///要获取其类型名称的SqlDbType
///适用的尺寸,例如创建nchar(n)类型,其中n是传入的尺寸。
///SQL语句中使用的SQL CE兼容类型
公共静态字符串GetSqlServerCETypeName(SqlDbType dbType,int size)
{
//转换依据:http://msdn.microsoft.com/en-us/library/ms173018.aspx
bool max=(size==int.MaxValue)?真:假;
bool over4k=(大小>4000)?真:假;
开关(dbType)
{
案例SqlDbType.BigInt:
返回“bigint”;
案例SqlDbType.Binary:
返回string.Format(“二进制({0})”,大小);
案例SqlDbType.Bit:
返回“位”;
案例SqlDbType.Char:
如果(超过4K)返回“ntext”;
else返回string.Format(“nchar({0})”,size);
等
最后是CREATETABLE语句:
/// <summary>
/// Genenerates a SQL CE compatible CREATE TABLE statement based on a schema obtained from
/// a SqlDataReader or a SqlCeDataReader.
/// </summary>
/// <param name="tableName">The name of the table to be created.</param>
/// <param name="schema">The schema returned from reader.GetSchemaTable().</param>
/// <returns>The CREATE TABLE... Statement for the given schema.</returns>
public static string GetCreateTableStatement(string tableName, DataTable schema)
{
StringBuilder builder = new StringBuilder();
builder.Append(string.Format("CREATE TABLE [{0}] (\n", tableName));
foreach (DataRow row in schema.Rows)
{
string typeName = row["DataType"].ToString();
Type type = Type.GetType(typeName);
string name = (string)row["ColumnName"];
int size = (int)row["ColumnSize"];
SqlDbType dbType = GetSqlDBTypeFromType(type);
builder.Append(name);
builder.Append(" ");
builder.Append(GetSqlServerCETypeName(dbType, size));
builder.Append(", ");
}
if (schema.Rows.Count > 0) builder.Length = builder.Length - 2;
builder.Append("\n)");
return builder.ToString();
}
//
///根据从中获取的架构生成与SQL CE兼容的CREATE TABLE语句
///SqlDataReader或SqlCeDataReader。
///
///要创建的表的名称。
///从reader.GetSchemaTable()返回的架构。
///给定架构的CREATETABLE…语句。
公共静态字符串GetCreateTableStatement(字符串表名、数据表架构)
{
StringBuilder=新的StringBuilder();
Append(string.Format(“创建表[{0}](\n”,tableName));
foreach(schema.Rows中的数据行)
{
字符串类型名称=行[“数据类型”]。ToString();
Type Type=Type.GetType(typeName);
字符串名称=(字符串)行[“ColumnName”];
int size=(int)行[“ColumnSize”];
SqlDbType dbType=GetSqlDBTypeFromType(type);
builder.Append(名称);
生成器。追加(“”);
Append(GetSqlServerCETypeName(dbType,size));
生成器。追加(“,”);
}
如果(schema.Rows.Count>0)builder.Length=builder.Length-2;
builder.Append(“\n)”);
返回builder.ToString();
}
我使用并更新了Ben Breen的代码:
- 已将GetSqlServerCETypeName更改为与所有类型一起使用
- 为整个数据集添加了一个函数
- 还有一些小的调整
/// <summary>
/// Gets the correct SqlDBType for a given .NET type. Useful for working with SQL CE.
/// </summary>
/// <param name="type">The .Net Type used to find the SqlDBType.</param>
/// <returns>The correct SqlDbType for the .Net type passed in.</returns>
public static SqlDbType GetSqlDBTypeFromType(Type type)
{
TypeConverter tc = TypeDescriptor.GetConverter(typeof(DbType));
if (/*tc.CanConvertFrom(type)*/ true)
{
DbType dbType = (DbType)tc.ConvertFrom(type.Name);
// A cheat, but the parameter class knows how to map between DbType and SqlDBType.
SqlCeParameter param = new SqlCeParameter();
param.DbType = dbType;
return param.SqlDbType; // The parameter class did the conversion for us!!
}
else
{
throw new Exception("Cannot get SqlDbType from: " + type.Name);
}
}
对于那些希望在常规SQL Server设置(非CE)上执行此操作的用户,我已设法修改此设置,以便在需要基于巨大csv文件(使用4.7.1.NET框架)以编程方式创建数据库表时使用SQL Server 2016设置。 请注意,这会检查最大列数,但不会检查最大行数,因此如果在处理大型csv文件时不考虑这一点,您可能会遇到错误
using System.Data;
using System.Data.SqlClient;
using System.ComponentModel;
//
//
//
private static DataTable GetDataTabletFromCSVFile(string csv_file_path)
{
DataTable csvData = new DataTable();
try
{
using (TextFieldParser csvReader = new TextFieldParser(csv_file_path))
{
csvReader.TextFieldType = FieldType.Delimited;
csvReader.SetDelimiters(new string[] { "," });
csvReader.HasFieldsEnclosedInQuotes = false;
string[] colFields = csvReader.ReadFields();
int columnCounter = 0;
foreach (string column in colFields)
{
if (columnCounter > 1023)
{
break; // the table has reached the maximum column size, either ignore the extra columns, or create additional linked tables (sounds like awful table design though).
}
DataColumn datecolumn = new DataColumn(column);
datecolumn.AllowDBNull = true;
csvData.Columns.Add(datecolumn);
columnCounter++;
}
while (!csvReader.EndOfData)
{
string[] fieldData = csvReader.ReadFields();
Array.Resize(ref fieldData, 1024); //max number of columns is 1024 in SQL table, and we're not going through the trouble of making a Sparse table.
//Making empty value as null
for (int i = 0; i < fieldData.Length; i++)
{
if (fieldData[i] == "")
{
fieldData[i] = null;
}
}
csvData.Rows.Add(fieldData);
}
}
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
return csvData;
}
/** <summary>
* Gets the correct SqlDBType for a given .NET type. Useful for working with SQL.
* </summary>
* <param name="type">The .Net Type used to find the SqlDBType.</param>
* <returns>The correct SqlDbType for the .Net type passed in.</returns>
*/
public static SqlDbType GetSqlDBTypeFromType(Type type)
{
TypeConverter tc = TypeDescriptor.GetConverter(typeof(DbType));
DbType dbType = (DbType)tc.ConvertFrom(type.Name);
// A cheat, but the parameter class knows how to map between DbType and SqlDBType.
SqlParameter param = new SqlParameter();
param.DbType = dbType;
return param.SqlDbType; // The parameter class did the conversion for us!!
}
/**
* <summary>
* The method gets the SQL type name for use in SQL Statements such as CREATE TABLE
* </summary>
* <param name="dbType">The SqlDbType to get the type name for</param>
* <param name="size">The size where applicable e.g. to create a nchar(n) type where n is the size passed in.</param>
* <returns>A string of the SQL compatible type for use in SQL Statements</returns>
*/
public static string GetSqlServerTypeName(SqlDbType dbType, int size)
{
// Conversions according to: https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/sql-server-data-type-mappings
bool max = (size == int.MaxValue || size == -1) ? true : false;
string returnVal = "";
if (max)
{
returnVal = Enum.GetName(typeof(SqlDbType), dbType) + " (max)";
}
else if (size > 0)
{
returnVal = string.Format(Enum.GetName(typeof(SqlDbType), dbType) + " ({0})", size);
}
else
{
returnVal = Enum.GetName(typeof(SqlDbType), dbType);
}
return returnVal;
}
/**
* <summary>
* Genenerates a SQL compatible CREATE TABLE statement based on a schema obtained from
* a SqlDataTable.
* </summary>
* <param name="table">The name of the table to be created.</param>
* <returns>The CREATE TABLE... Statement for the given data table.</returns>
*/
public static string GetCreateTableStatement(DataTable table)
{
StringBuilder builder = new StringBuilder();
builder.Append(string.Format("CREATE TABLE [{0}] (", table.TableName));
int primaryCol = 0;
foreach (DataColumn col in table.Columns)
{
SqlDbType dbType = GetSqlDBTypeFromType(col.DataType);
builder.Append("[");
builder.Append(col.ColumnName);
builder.Append("]");
builder.Append(" ");
builder.Append(GetSqlServerTypeName(dbType, col.MaxLength));
//if on first column, assume it's a "PRIMARY KEY" (for now)
if(primaryCol == 0)
{
builder.Append(" PRIMARY KEY");
}
builder.Append(", ");
primaryCol++;
}
if (table.Columns.Count > 0) builder.Length = builder.Length - 2;
builder.Append(")");
return builder.ToString();
}
/**
* <summary>
* Genenerates a SQL compatible CREATE TABLE statement based on a schema obtained from
* a SqlDataTable.
* </summary>
* <param name="dtable">The name of the table to be created.</param>
* <param name="conn">The SQL Connection to the database that the table will be created in.</param>
*/
public static void CreateFromDataTable(DataTable dTable, SqlConnection conn)
{
bool openedHere = false;
if (conn.State == ConnectionState.Closed)
{
conn.Open();
openedHere = true;
}
SqlCommand cmd;
string createSql = GetCreateTableStatement(dTable);
Console.WriteLine(createSql);
cmd = new SqlCommand(createSql, conn);
Console.WriteLine(cmd.ExecuteNonQuery());
if (openedHere)
{
conn.Close();
}
}
使用系统数据;
使用System.Data.SqlClient;
使用系统组件模型;
//
//
//
私有静态数据表GetDataTabletFromCSVFile(字符串csv\u文件\u路径)
{
DataTable csvData=新DataTable();
尝试
{
使用(TextFieldParser csvReader=新的TextFieldParser(csv_文件_路径))
{
csvReader.TextFieldType=FieldType.Delimited;
SetDelimiters(新字符串[]{“,”});
csvReader.HasFieldsEnclosedInQuotes=false;
字符串[]colFields=csvReader.ReadFields();
int columnCounter=0;
foreach(colFields中的字符串列)
{
如果(列计数器>1023)
{
break;//表已达到最大列大小,请忽略额外的列,或创建额外的链接表(尽管听起来像糟糕的表设计)。
}
DataColumn datecolumn=新的DataColumn(列);
datecolumn.AllowDBNull=true;
csvData.Columns.Add(datecolumn);
列计数器++;
}
而(!csvReader.EndOfData)
{
字符串[]fieldData=csvReader.ReadFields();
A.
/// <summary>
/// Genenerates a SQL CE compatible CREATE TABLE statement based on a schema obtained from
/// a SqlDataReader or a SqlCeDataReader.
/// </summary>
/// <param name="tableName">The name of the table to be created.</param>
/// <param name="schema">The schema returned from reader.GetSchemaTable().</param>
/// <returns>The CREATE TABLE... Statement for the given schema.</returns>
public static string GetCreateTableStatement(DataTable table)
{
StringBuilder builder = new StringBuilder();
builder.Append(string.Format("CREATE TABLE [{0}] (", table.TableName));
foreach (DataColumn col in table.Columns)
{
SqlDbType dbType = GetSqlDBTypeFromType(col.DataType);
builder.Append("[");
builder.Append(col.ColumnName);
builder.Append("]");
builder.Append(" ");
builder.Append(GetSqlServerCETypeName(dbType, col.MaxLength));
builder.Append(", ");
}
if (table.Columns.Count > 0) builder.Length = builder.Length - 2;
builder.Append(")");
return builder.ToString();
}
public static void CreateFromDataset(DataSet set, SqlCeConnection conn)
{
conn.Open();
SqlCeCommand cmd;
foreach (DataTable table in set.Tables)
{
string createSql = copyDB.GetCreateTableStatement(table);
Console.WriteLine(createSql);
cmd = new SqlCeCommand(createSql, conn);
Console.WriteLine(cmd.ExecuteNonQuery());
}
conn.Close();
}
}
using System.Data;
using System.Data.SqlClient;
using System.ComponentModel;
//
//
//
private static DataTable GetDataTabletFromCSVFile(string csv_file_path)
{
DataTable csvData = new DataTable();
try
{
using (TextFieldParser csvReader = new TextFieldParser(csv_file_path))
{
csvReader.TextFieldType = FieldType.Delimited;
csvReader.SetDelimiters(new string[] { "," });
csvReader.HasFieldsEnclosedInQuotes = false;
string[] colFields = csvReader.ReadFields();
int columnCounter = 0;
foreach (string column in colFields)
{
if (columnCounter > 1023)
{
break; // the table has reached the maximum column size, either ignore the extra columns, or create additional linked tables (sounds like awful table design though).
}
DataColumn datecolumn = new DataColumn(column);
datecolumn.AllowDBNull = true;
csvData.Columns.Add(datecolumn);
columnCounter++;
}
while (!csvReader.EndOfData)
{
string[] fieldData = csvReader.ReadFields();
Array.Resize(ref fieldData, 1024); //max number of columns is 1024 in SQL table, and we're not going through the trouble of making a Sparse table.
//Making empty value as null
for (int i = 0; i < fieldData.Length; i++)
{
if (fieldData[i] == "")
{
fieldData[i] = null;
}
}
csvData.Rows.Add(fieldData);
}
}
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
return csvData;
}
/** <summary>
* Gets the correct SqlDBType for a given .NET type. Useful for working with SQL.
* </summary>
* <param name="type">The .Net Type used to find the SqlDBType.</param>
* <returns>The correct SqlDbType for the .Net type passed in.</returns>
*/
public static SqlDbType GetSqlDBTypeFromType(Type type)
{
TypeConverter tc = TypeDescriptor.GetConverter(typeof(DbType));
DbType dbType = (DbType)tc.ConvertFrom(type.Name);
// A cheat, but the parameter class knows how to map between DbType and SqlDBType.
SqlParameter param = new SqlParameter();
param.DbType = dbType;
return param.SqlDbType; // The parameter class did the conversion for us!!
}
/**
* <summary>
* The method gets the SQL type name for use in SQL Statements such as CREATE TABLE
* </summary>
* <param name="dbType">The SqlDbType to get the type name for</param>
* <param name="size">The size where applicable e.g. to create a nchar(n) type where n is the size passed in.</param>
* <returns>A string of the SQL compatible type for use in SQL Statements</returns>
*/
public static string GetSqlServerTypeName(SqlDbType dbType, int size)
{
// Conversions according to: https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/sql-server-data-type-mappings
bool max = (size == int.MaxValue || size == -1) ? true : false;
string returnVal = "";
if (max)
{
returnVal = Enum.GetName(typeof(SqlDbType), dbType) + " (max)";
}
else if (size > 0)
{
returnVal = string.Format(Enum.GetName(typeof(SqlDbType), dbType) + " ({0})", size);
}
else
{
returnVal = Enum.GetName(typeof(SqlDbType), dbType);
}
return returnVal;
}
/**
* <summary>
* Genenerates a SQL compatible CREATE TABLE statement based on a schema obtained from
* a SqlDataTable.
* </summary>
* <param name="table">The name of the table to be created.</param>
* <returns>The CREATE TABLE... Statement for the given data table.</returns>
*/
public static string GetCreateTableStatement(DataTable table)
{
StringBuilder builder = new StringBuilder();
builder.Append(string.Format("CREATE TABLE [{0}] (", table.TableName));
int primaryCol = 0;
foreach (DataColumn col in table.Columns)
{
SqlDbType dbType = GetSqlDBTypeFromType(col.DataType);
builder.Append("[");
builder.Append(col.ColumnName);
builder.Append("]");
builder.Append(" ");
builder.Append(GetSqlServerTypeName(dbType, col.MaxLength));
//if on first column, assume it's a "PRIMARY KEY" (for now)
if(primaryCol == 0)
{
builder.Append(" PRIMARY KEY");
}
builder.Append(", ");
primaryCol++;
}
if (table.Columns.Count > 0) builder.Length = builder.Length - 2;
builder.Append(")");
return builder.ToString();
}
/**
* <summary>
* Genenerates a SQL compatible CREATE TABLE statement based on a schema obtained from
* a SqlDataTable.
* </summary>
* <param name="dtable">The name of the table to be created.</param>
* <param name="conn">The SQL Connection to the database that the table will be created in.</param>
*/
public static void CreateFromDataTable(DataTable dTable, SqlConnection conn)
{
bool openedHere = false;
if (conn.State == ConnectionState.Closed)
{
conn.Open();
openedHere = true;
}
SqlCommand cmd;
string createSql = GetCreateTableStatement(dTable);
Console.WriteLine(createSql);
cmd = new SqlCommand(createSql, conn);
Console.WriteLine(cmd.ExecuteNonQuery());
if (openedHere)
{
conn.Close();
}
}