데이터 리더에서 데이터 테이블 채우기
저는 C # (MS VS2008)에서 기본적인 작업을하고 특정 코드보다 적절한 디자인에 대해 더 많은 질문이 있습니다.
데이터 테이블을 만든 다음 데이터 숨김 기 (SQL 저장 프로 시저 기반)에서 데이터 테이블을로드합니다. 내가 궁금한 것은 데이터 테이블을로드하는 가장 방법이 있는지 여부입니다.
나에게 유일한 단점은 동시에 문에 추가하려는 필드를 수동으로 입력해야한다는 것입니다.하지만 SP의 모든 필드가 하나만 선택하는 것을 선택하기 때문에 자동화하는 방법도 있습니다. , 그러나 그것은 내 눈에 큰 문제가 아닙니다.
내가하는 일의 전체 아래에 코드 스 니펫을 포함지만, 나 보유 코드 자체가 눈 에지 심지어 내가 요청하는 내용도 포함되지 않습니다. 더 나아가 내 방법론에 대해 궁금해하면서 내 전략이 잘못 또는 비효율적 인 경우 나중에 코드 도움을 요청하겠습니다.
var dtWriteoffUpload = new DataTable();
dtWriteoffUpload.Columns.Add("Unit");
dtWriteoffUpload.Columns.Add("Year");
dtWriteoffUpload.Columns.Add("Period");
dtWriteoffUpload.Columns.Add("Acct");
dtWriteoffUpload.Columns.Add("Descr");
dtWriteoffUpload.Columns.Add("DEFERRAL_TYPE");
dtWriteoffUpload.Columns.Add("NDC_Indicator");
dtWriteoffUpload.Columns.Add("Mgmt Cd");
dtWriteoffUpload.Columns.Add("Prod");
dtWriteoffUpload.Columns.Add("Node");
dtWriteoffUpload.Columns.Add("Curve_Family");
dtWriteoffUpload.Columns.Add("Sum Amount");
dtWriteoffUpload.Columns.Add("Base Curr");
dtWriteoffUpload.Columns.Add("Ledger");
cmd = util.SqlConn.CreateCommand();
cmd.CommandTimeout = 1000;
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "proc_writeoff_data_details";
cmd.Parameters.Add("@whoAmI", SqlDbType.VarChar).Value =
WindowsIdentity.GetCurrent().Name;
cmd.Parameters.Add("@parmEndDateKey", SqlDbType.VarChar).Value = myMostRecentActualDate;
cmd.Parameters.Add("@countrykeys", SqlDbType.VarChar).Value = myCountryKey;
cmd.Parameters.Add("@nodekeys", SqlDbType.VarChar).Value = "1,2";
break;
dr = cmd.ExecuteReader();
while (dr.Read())
{
dtWriteoffUpload.Rows.Add(dr["country name"].ToString(), dr["country key"].ToString());
}
를 허용하는 메소드를 DataTable
사용하여 데이터에서 직접 로드 할 수 있습니다 .Load()
IDataReader
var dataReader = cmd.ExecuteReader();
var dataTable = new DataTable();
dataTable.Load(dataReader);
아래 코드를 확인하세요. 자동으로 DataTable로 변환됩니다.
private void ConvertDataReaderToTableManually()
{
SqlConnection conn = null;
try
{
string connString = ConfigurationManager.ConnectionStrings["NorthwindConn"].ConnectionString;
conn = new SqlConnection(connString);
string query = "SELECT * FROM Customers";
SqlCommand cmd = new SqlCommand(query, conn);
conn.Open();
SqlDataReader dr = cmd.ExecuteReader(CommandBehavior.CloseConnection);
DataTable dtSchema = dr.GetSchemaTable();
DataTable dt = new DataTable();
// You can also use an ArrayList instead of List<>
List<DataColumn> listCols = new List<DataColumn>();
if (dtSchema != null)
{
foreach (DataRow drow in dtSchema.Rows)
{
string columnName = System.Convert.ToString(drow["ColumnName"]);
DataColumn column = new DataColumn(columnName, (Type)(drow["DataType"]));
column.Unique = (bool)drow["IsUnique"];
column.AllowDBNull = (bool)drow["AllowDBNull"];
column.AutoIncrement = (bool)drow["IsAutoIncrement"];
listCols.Add(column);
dt.Columns.Add(column);
}
}
// Read rows from DataReader and populate the DataTable
while (dr.Read())
{
DataRow dataRow = dt.NewRow();
for (int i = 0; i < listCols.Count; i++)
{
dataRow[((DataColumn)listCols[i])] = dr[i];
}
dt.Rows.Add(dataRow);
}
GridView2.DataSource = dt;
GridView2.DataBind();
}
catch (SqlException ex)
{
// handle error
}
catch (Exception ex)
{
// handle error
}
finally
{
conn.Close();
}
}
를로드하려는 경우 대신 DataTable
다음을 활용하십시오 SqlDataAdapter
.
DataTable dt = new DataTable();
using (SqlConnection c = new SqlConnection(cString))
using (SqlDataAdapter sda = new SqlDataAdapter(sql, c))
{
sda.SelectCommand.CommandType = CommandType.StoredProcedure;
sda.SelectCommand.Parameters.AddWithValue("@parm1", val1);
...
sda.Fill(dt);
}
필요조차 없습니다. 그냥를 생성 DataTable
하고 Fill
.
여기에 cString
연결 암호화이 및 sql
저장 프로 시저 명령입니다.
Sagi가 답변에서 언급했듯이 DataTable.Load는 좋은 솔루션입니다. 단일 판독기에서 여러 테이블을로드하려는 경우 DataReader.NextResult를 호출 할 필요가 없습니다. DataTable.Load 메서드는 또한 판독기를 다음 결과 집합 (있는 경우)으로 이동합니다.
// Read every result set in the data reader.
while (!reader.IsClosed)
{
DataTable dt = new DataTable();
// DataTable.Load automatically advances the reader to the next result set
dt.Load(reader);
items.Add(dt);
}
나는 이것도 조사했고, SqlDataAdapter.Fill 메서드를 SqlDataReader.Load 함수와 비교 한 후 SqlDataAdapter.Fill 메서드가 내가 사용한 결과 집합보다 두 배 이상 빠르다는 것을 발견했습니다.
사용 된 코드 :
[TestMethod]
public void SQLCommandVsAddaptor()
{
long AdapterFillLargeTableTime, readerLoadLargeTableTime, AdapterFillMediumTableTime, readerLoadMediumTableTime, AdapterFillSmallTableTime, readerLoadSmallTableTime, AdapterFillTinyTableTime, readerLoadTinyTableTime;
string LargeTableToFill = "select top 10000 * from FooBar";
string MediumTableToFill = "select top 1000 * from FooBar";
string SmallTableToFill = "select top 100 * from FooBar";
string TinyTableToFill = "select top 10 * from FooBar";
using (SqlConnection sconn = new SqlConnection("Data Source=.;initial catalog=Foo;persist security info=True; user id=bar;password=foobar;"))
{
// large data set measurements
AdapterFillLargeTableTime = MeasureExecutionTimeMethod(sconn, LargeTableToFill, ExecuteDataAdapterFillStep);
readerLoadLargeTableTime = MeasureExecutionTimeMethod(sconn, LargeTableToFill, ExecuteSqlReaderLoadStep);
// medium data set measurements
AdapterFillMediumTableTime = MeasureExecutionTimeMethod(sconn, MediumTableToFill, ExecuteDataAdapterFillStep);
readerLoadMediumTableTime = MeasureExecutionTimeMethod(sconn, MediumTableToFill, ExecuteSqlReaderLoadStep);
// small data set measurements
AdapterFillSmallTableTime = MeasureExecutionTimeMethod(sconn, SmallTableToFill, ExecuteDataAdapterFillStep);
readerLoadSmallTableTime = MeasureExecutionTimeMethod(sconn, SmallTableToFill, ExecuteSqlReaderLoadStep);
// tiny data set measurements
AdapterFillTinyTableTime = MeasureExecutionTimeMethod(sconn, TinyTableToFill, ExecuteDataAdapterFillStep);
readerLoadTinyTableTime = MeasureExecutionTimeMethod(sconn, TinyTableToFill, ExecuteSqlReaderLoadStep);
}
using (StreamWriter writer = new StreamWriter("result_sql_compare.txt"))
{
writer.WriteLine("10000 rows");
writer.WriteLine("Sql Data Adapter 100 times table fill speed 10000 rows: {0} milliseconds", AdapterFillLargeTableTime);
writer.WriteLine("Sql Data Reader 100 times table load speed 10000 rows: {0} milliseconds", readerLoadLargeTableTime);
writer.WriteLine("1000 rows");
writer.WriteLine("Sql Data Adapter 100 times table fill speed 1000 rows: {0} milliseconds", AdapterFillMediumTableTime);
writer.WriteLine("Sql Data Reader 100 times table load speed 1000 rows: {0} milliseconds", readerLoadMediumTableTime);
writer.WriteLine("100 rows");
writer.WriteLine("Sql Data Adapter 100 times table fill speed 100 rows: {0} milliseconds", AdapterFillSmallTableTime);
writer.WriteLine("Sql Data Reader 100 times table load speed 100 rows: {0} milliseconds", readerLoadSmallTableTime);
writer.WriteLine("10 rows");
writer.WriteLine("Sql Data Adapter 100 times table fill speed 10 rows: {0} milliseconds", AdapterFillTinyTableTime);
writer.WriteLine("Sql Data Reader 100 times table load speed 10 rows: {0} milliseconds", readerLoadTinyTableTime);
}
Process.Start("result_sql_compare.txt");
}
private long MeasureExecutionTimeMethod(SqlConnection conn, string query, Action<SqlConnection, string> Method)
{
long time; // know C#
// execute single read step outside measurement time, to warm up cache or whatever
Method(conn, query);
// start timing
time = Environment.TickCount;
for (int i = 0; i < 100; i++)
{
Method(conn, query);
}
// return time in milliseconds
return Environment.TickCount - time;
}
private void ExecuteDataAdapterFillStep(SqlConnection conn, string query)
{
DataTable tab = new DataTable();
conn.Open();
using (SqlDataAdapter comm = new SqlDataAdapter(query, conn))
{
// Adapter fill table function
comm.Fill(tab);
}
conn.Close();
}
private void ExecuteSqlReaderLoadStep(SqlConnection conn, string query)
{
DataTable tab = new DataTable();
conn.Open();
using (SqlCommand comm = new SqlCommand(query, conn))
{
using (SqlDataReader reader = comm.ExecuteReader())
{
// IDataReader Load function
tab.Load(reader);
}
}
conn.Close();
}
결과 :
10000 rows:
Sql Data Adapter 100 times table fill speed 10000 rows: 11782 milliseconds
Sql Data Reader 100 times table load speed 10000 rows: 26047 milliseconds
1000 rows:
Sql Data Adapter 100 times table fill speed 1000 rows: 984 milliseconds
Sql Data Reader 100 times table load speed 1000 rows: 2031 milliseconds
100 rows:
Sql Data Adapter 100 times table fill speed 100 rows: 125 milliseconds
Sql Data Reader 100 times table load speed 100 rows: 235 milliseconds
10 rows:
Sql Data Adapter 100 times table fill speed 10 rows: 32 milliseconds
Sql Data Reader 100 times table load speed 10 rows: 93 milliseconds
성능 문제의 경우 SqlDataAdapter.Fill 메서드를 사용하는 것이 훨씬 더 효율적입니다. 그래서 당신이 발에 자신을 쏘고 싶지 않다면 그것을 사용하십시오. 작고 큰 데이터 세트에 대해 더 빠르게 작동합니다.
참고 URL : https://stackoverflow.com/questions/18961938/populate-data-table-from-data-reader
'IT' 카테고리의 다른 글
TypeError : ObjectId ( '')는 JSON 화 가능하지 않습니다. (0) | 2020.09.04 |
---|---|
jQuery를 사용하여 마우스 포커스를 설정하고 커서를 입력 끝으로 이동 (0) | 2020.09.04 |
한 줄에있는 단어 사이에 둘 이상의 공백이있는 항목을 검색하는 방법 (0) | 2020.09.03 |
외모 전환을 시작 / 종료하기위한 불균형 통화 (0) | 2020.09.03 |
스칼라 상수에 대한 명명 규칙? (0) | 2020.09.03 |