PDA

View Full Version : گفتگو: Import یک DataTable با کل ساختار به SQL Server



Saeed_m_Farid
چهارشنبه 09 دی 1388, 17:53 عصر
سلام
میخواستم ببینم از دوستان کسی تا حالا یه DataTable رو از حافظه به SQL-Server انتقال داده؟ البته میدونم که حتماً اینکار رو انجام دادین ولی راه حلی که پیشنهاد می دید چیه؟
برای روشن تر شدن مساله، باید بگم که SQL-Server اجباراً 2000 هست و من یه DataSet دارای جدول و مقادیر پر شده، دارم که میخوام Tables[0] 0 اش رو با ساختار، محتویات و نام جدول بزیرم تو SQL-Server؛ با این فرض که اگه جدول موردنظر تو دیتابیس موجود بود حذفش کنم (چون ممکنه فیلدها تفاوت داشته باشن) و DataTable موردنظر رو جایگزین کنم.
تو CodeProject یه راه حل خیلی جالبی واسه این موضوع هست (اینجا (http://www.codeproject.com/KB/database/DataTableToDataBase.aspx)) ، ولی مشکلی که داره اینه که از SqlServer Management Objects یا SMO استفاده می کنه و تا اونجایی که من میدونم SMO فقط با SqlServer 2005 کار میکنه!:افسرده: درواقع من اصلاً نتونستم Microsoft.SqlServer.Management.Smo رو include کنم و از همون اولش فقط کد رو می دیدم و دلم آب میشد!
راه حل دیگه این هست که من لیست تمام جداول SQL-Server رو بگیرم و اگه نام DataTable با نام جدول یکی بود جدول رو ALTER کنم و بعد پایان این پروسه زمانبر! دوباره تمام جداول رو CREATE کرده و مثلاً ازطریق SqlBulkCopy جداول جدید و مقادیرشون رو بزنم که خوب هم نوشتن این کد زمانبر هست و هم زمان اجرای زیادی می گیره؛ این سولوشن رو تا یه جاهایی جلو بردم که اگه خواستین بذارم تا ببینید ...

میخواستم نظر شما رو هم بیزحمت بدونم، ممنون.

meysam_pro
چهارشنبه 09 دی 1388, 18:55 عصر
راه حلی که پیشنهاد می دید چیه؟



var cp = new SqlBulkCopy(CnString)
{
DestinationTableName = tableName
};
cp.WriteToServer(dt);

البته فکر کنم تو SQL 2000 جواب نده!(از کامنت bp استفاده می کنه) و یک نکته هم داره ، که ساختار باید با دقیقا مطابق باشه!

Saeed_m_Farid
پنج شنبه 10 دی 1388, 11:07 صبح
var cp = new SqlBulkCopy(CnString)
{
DestinationTableName = tableName
};
cp.WriteToServer(dt);

البته فکر کنم تو SQL 2000 جواب نده!(از کامنت bp استفاده می کنه) و یک نکته هم داره ، که ساختار باید با دقیقا مطابق باشه!
دوست عزیز، من که عرض کردم :
مثلاً ازطریق SqlBulkCopy جداول جدید و مقادیرشون رو بزنم و در SQL-Server 2000 هم کار میکنه، کدی هم که واسش نوشتم و زیر بار هست :
static void CopySQLData(DataTable sourceTable,
SqlConnection destConnection)
{
using (SqlBulkCopy bulkCopy = new SqlBulkCopy(destConnection))
{
bulkCopy.DestinationTableName = sourceTable.TableName;
bulkCopy.BatchSize = 500;
bulkCopy.NotifyAfter = 1000;

bulkCopy.SqlRowsCopied +=
new SqlRowsCopiedEventHandler(bulkCopy_SqlRowsCopied);

bulkCopy.WriteToServer(sourceTable);
bulkCopy.Close();
}
}

مشکل من یه چیز دیگه بود :

DataTable رو با ساختار، محتویات و نام جدول بزیرم تو SQL-Server؛ با این فرض که اگه جدول موردنظر تو دیتابیس موجود بود حذفش کنم (چون ممکنه فیلدها تفاوت داشته باشن) و DataTable موردنظر رو جایگزین کنم.بازم ممنون که حداقل یکی از پست های من مشاهده شد، داشتم فکر میکردم واسه سایر کاربران نامرئی شدم (همه جا فقط آقای کشاورز من رو می بینه و بس)!

esmaeily-hosein
پنج شنبه 10 دی 1388, 13:54 عصر
میتونی مقادیر Datatable را در داخل یک xml بریزی و بعد اونور اونو InsertSelect کنی !
اگر خواستی بگو نمونه کدشو بزارم .

meysam_pro
پنج شنبه 10 دی 1388, 16:08 عصر
DataTable رو با ساختار، محتویات و نام جدول بزیرم تو SQL-Server؛ با این فرض که اگه جدول موردنظر تو دیتابیس موجود بود حذفش کنم (چون ممکنه فیلدها تفاوت داشته باشن) و DataTable موردنظر رو جایگزین کنم.
چرا میزنی جناب موسوی؟(Just kidding)
ساختار رو از محتویات XMLی که دیتاتیبل داره بخونیم و بقیه رو تو SQL Server ادامه بدیم(از طریق xtype ها در سکوئل، نام جدول و فیلدهاش رو خونده و....) البته و....
که فکر کنم به دردتون نمیخوره بازم!

Saeed_m_Farid
شنبه 12 دی 1388, 13:31 عصر
میتونی مقادیر Datatable را در داخل یک xml بریزی و بعد اونور اونو InsertSelect کنی !
اگر خواستی بگو نمونه کدشو بزارم .
ممنون، ولی بازم باید بگم من تو کپی داده ها مشکلی ندارم! ضمناً DataTable خودش در اصل دارای ساختار XML هست و نیازی به ریختن مجدد داخل XML نیست، اگه منظورتون WriteXml, WriteXmlSchema هست که :


اولاً باید برای اینکار تمام DataTable (شامل Data و Schema) رو از حافظه بار کنم رو هارد! که هم وقت گیر هست (بعلت حجم داده و تفاوت سرعت رم با هارد!!!) و هم نیاز به نوشتن و خوندن های مکرر روی هارد هست که با این هاردها، خیلی زود از بین میرن!
ثانیاً باید توجه کنید که یک زمان نسبتاً طولانی قبلش صرف Select از جداول Source شده؛ حالا بیایم بازم از Result مون Select کنیم که برنامه عملاً بی مصرف میشه! من برای این کار SqlBulkCopy رو استفاده کردم که هم برای حجم بالای داده جواب میده و هم انتقال داده به یک Batch Size مشخصی رسید، یک Notify تنظیم میشه که کار خاصی اگه خواستیم انجام بدیم یا حتی کپی رو RollBack کنیم، قابل انجام باشه و ...

ساختار و DataType و ... : مشکل تو اینهاست، یعنی DataTable ای که دست من میرسه (و ذاتاً XML هست) تو Schema اش هیچ جزئیاتی از نوع داده نیست، تنها یکی از type های xs:decimal، xs:string یا xs:float رو شامل میشه که اندازه و نوع دقیق توش ذکر نشده!
الان هم مشکل رو با کدی که تو پست قبل ذکر کردم (برای کپی داده) و کد زیر (برای انتقال ساختار)؛ فعلاً حل کردم، چیزی که من میخواستم بدونم این بود که : آیا راه حل اتوماتیک (یا پیش بینی شده) واسه اینکار هست یا نه؛ مثلاً SMO که تو پست اول ذکر کردم یا راه حلهای LINQ و ... که مثل اینکه نیست یا اگه هم باشه واسه نسخه های جدید SQL-Server هست.

private bool transferTable(string name, DataTable table, bool bTableExist)
{
bool Result = false;
try
{
using (var cmd = new SqlCommand("", g_SqlConn))
{
if (bTableExist)
{
cmd.CommandText = "DROP TABLE \"" + name + "\"";
cmd.ExecuteNonQuery();
cmd.CommandText = cmd.CommandText.Replace("DROP", "CREATE");
}
else
cmd.CommandText = cmd.CommandText = "CREATE TABLE \"" + name + "\"";

cmd.CommandText += " \n (\n";
foreach (DataColumn cl in table.Columns)
{
cmd.CommandText += ' ' + cl.ColumnName + ' ' ;
switch (cl.DataType.ToString())
{
case ("System.Single"):
cmd.CommandText += " float, \n";
break;
case ("System.Double"):
cmd.CommandText += " double, \n";
break;
case ("System.Decimal"):
cmd.CommandText += " int, \n";
break;
default:
cmd.CommandText += " varchar(255), \n";
break;
}
if (cl.Unique)
cmd.CommandText += " UNIQUE \n";
}
int lastcomma = cmd.CommandText.LastIndexOf(',');
if (lastcomma >= 0)
cmd.CommandText = cmd.CommandText.Remove(lastcomma, 1);
else
{
addLog("[WR] Tabale <" + name + @"> has not SELECT privilege!,
so you can't transfer it! Delete table name from list and try again...");
return false;
}
cmd.CommandText += ")";
cmd.ExecuteNonQuery();
Thread.Sleep(500);
CopySQLData(name, table, g_SqlConn); // Copy DataTable Contents [with SqlBulkCopy] ...
Result = true;
}
}
catch (Exception ex)
{
addLog("[ER] Error[CreateSqlTable]: " + ex.Message);
Result = false;
}
return Result;
}



چرا میزنی جناب موسوی؟(Just kidding) ... ساختار رو از محتویات XMLی که دیتاتیبل داره بخونیم ...

من همچین جسارتی نکردم، ضمناً دقیقاً همین کار رو می کنم (توضیحات بالا) : ^
ممنون.

fidelio
پنج شنبه 25 شهریور 1389, 16:29 عصر
من مشکل اصلی ام اینه که موقع ریختن datatable داخل table ارور می ده که امکان تبدلی نوع Int به استرینگ نیست در صورتی که من حتا همه ی فیلدهام رشته است.

کسی می تونه کمکی کنه؟