【发布时间】:2011-01-20 13:06:53
【问题描述】:
使用 sql server 表的架构创建 Empty DataTable 对象的最佳方法是什么?
【问题讨论】:
标签: c# .net sql-server ado.net datatable
使用 sql server 表的架构创建 Empty DataTable 对象的最佳方法是什么?
【问题讨论】:
标签: c# .net sql-server ado.net datatable
假设您可以连接到包含您想要复制的表的 SQL 数据库,此时您可以使用传统的结果集到数据表转换,使用
select * from <tablename> where 1=2
作为您的源查询。
这将返回一个带有源表结构的空结果集。
【讨论】:
尝试:
SELECT TOP 0 * FROM [TableName]
并使用 SQLDataAdapter 填充数据集,然后从该数据集中获取表。
【讨论】:
我认为值得一提的是SET FMTONLY:
SET FMTONLY ON;
SELECT * FROM SomeTable
SET FMTONLY OFF;
当 SET FMTONLY 开启时,由于请求,没有任何行被处理或发送到客户端。
这很方便的原因是因为您可以提供任何查询/存储过程并仅返回结果集的元数据。
【讨论】:
您可以随时创建自己的:
DataTable table = new DataTable("TableName");
table.Columns.Add(new DataColumn("Col1", typeof(int)));
table.Columns.Add(new DataColumn("Col2", typeof(int)));
table.Columns.Add(new DataColumn("Col3", typeof(string)));
table.Columns.Add(new DataColumn("Col4", typeof(int)));
table.Columns.Add(new DataColumn("Col5", typeof(string)));
明显的缺点是,每当数据库架构发生变化时,您都必须更新代码。
【讨论】:
这就是我所做的:
var conn = new SqlConnection("someConnString");
var cmd = new SqlCommand("SET FMTONLY ON; SELECT * FROM MyTable; SET FMTONLY OFF;",conn);
var dt = new DataTable();
conn.Open();
dt.Load(cmd.ExecuteReader());
conn.Dispose();
效果很好。感谢 AdaTheDev。
【讨论】:
这行得通:
Class BlankTableWithSourceTableSchema
Inherits DataTable
Public Sub New(ByVal connstr As String, ByVal sourcetable As String)
Try
Using connection As SqlServerCe.SqlCeConnection = New SqlServerCe.SqlCeConnection(connstr)
Dim adapter As SqlServerCe.SqlCeDataAdapter = New SqlServerCe.SqlCeDataAdapter("SELECT * FROM " & sourcetable, connection)
adapter.TableMappings.Add("Table", "ABlankTable")
adapter.FillSchema(Me, SchemaType.Mapped)
End Using
Catch ex As Exception
End Try
End Sub
End Class
【讨论】:
Class BlankTableWithSourceTableSchema
Inherits DataTable
Public Sub New(ByVal connstr As String, ByVal sourcetable As String)
Try
Using connection As SqlServerCe.SqlCeConnection = New SqlServerCe.SqlCeConnection(connstr)
Dim adapter As SqlServerCe.SqlCeDataAdapter = New SqlServerCe.SqlCeDataAdapter("SELECT * FROM " & sourcetable, connection)
adapter.TableMappings.Add("Table", "ABlankTable")
adapter.FillSchema(Me, SchemaType.Mapped)
End Using
Catch ex As Exception
End Try
End Sub
End Class
【讨论】:
所有这些解决方案都是正确的,但是如果您想要一个针对这种情况进行简化的纯代码解决方案。
由于在 ExecuteReader 函数上指定了 CommandBehavior.SchemaOnly,因此此解决方案中不返回任何数据 (Command Behavior Documentation)
CommandBehavior.SchemaOnly 解决方案将添加 SET FMTONLY ON;为您执行查询之前的 sql,因此它可以保持您的代码干净。
public static DataTable GetDataTableSchemaFromTable(string tableName, SqlConnection sqlConn, SqlTransaction transaction)
{
DataTable dtResult = new DataTable();
using (SqlCommand command = sqlConn.CreateCommand())
{
command.CommandText = String.Format("SELECT TOP 1 * FROM {0}", tableName);
command.CommandType = CommandType.Text;
if (transaction != null)
{
command.Transaction = transaction;
}
SqlDataReader reader = command.ExecuteReader(CommandBehavior.SchemaOnly);
dtResult.Load(reader);
}
return dtResult;
}
【讨论】:
我知道这是一个老问题,特定于 SQL Server。但是,如果您正在寻找适用于不同数据库的通用解决方案,请使用 Richard 的解决方案,但将其修改为使用 "SELECT * FROM {0} WHERE 1=0" 并将类型更改为使用通用 ADO.Net 类型 IDataReader、IDbCommand 等。
大多数现代关系数据库都足够智能,可以识别 1=0 条件,并且不会像常规表扫描查询那样运行它。我在 SQL Server、Oracle 和 DB2 上试过这个,表也只有几亿条记录。所有都在几毫秒内返回空结果。
【讨论】:
这是我所做的,它提供了一个可以使用的空白 DataTable:
SqlConnection _sqlConnection = new SqlConnection ();
_sqlConnection.ConnectionString = @"Data Source=<SQL_Server/Instance>; Initial Catalog=<database_name>; Integrated Security=False; User ID=<user_id>;Password=<passowrd>";
_sqlConnection.Open ();
SqlCommand _sqlCommand = new SqlCommand ( "select * from DatabaseName.dbo.viewName", _sqlConnection );
_dataSet = new DataSet ();
_sqlDataAdapter = new SqlDataAdapter ( _sqlCommand );
_sqlDataAdapter.Fill ( _dataSet );
_schemaTable = new DataTable ();
_sqlDataAdapter.FillSchema ( _schemaTable, SchemaType.Source );
dataGridView.DataSource = _schemaTable;
_sqlConnection.Close ();
【讨论】: