( تعداد نمایش : 2476 )

فرستادن یک آرایه یا DataTable به یک Stored Procedure

آیا تا بحال خواسته اید که یک DataTable یا یک آرایه که شامل ده ها، ده ها هزار ( و یا حتی میلیون ها ) رکورد می باشد را در فقط یک فراخوانی پایگاه داده به یکStored Procedure در SQL Server 2000 بفرستید ؟ و یا تا بحال خواسته اید که لیست شناسه های رکوردها را برای انتخاب یا حذف به یک Stored Procedure بفرستید ؟ اگر این کارها را انجام نداده اید و یا نتوانستید که برای انجام آن راه حلی پیدا کنید پس راه حل این کار را می توانید در اینجا ببینید .

حقه انجام این کار تبدیل لیست های داده به آرایه ای از بایت می باشد ، که این آرایه ها را سپس به عنوان پارامتر از نوع image به Stored Procedure می فرستیم . سپس در Stored Procedure این تصویر به یک جدول متغیر که شامل داده های اصلی می باشد تبدیل می شود . تابع SQL Server زیر یکی از توابع تبدیل پارامتر از نوع image به یک جدول متغیر می باشد . این تابع یک جدول از نوع متغیر varchar ایجاد می کند .

CREATE FUNCTION dbo.GetTableVarchar(@Data image)
RETURNS @DataTable
TABLE (RowID int primary key IDENTITY , Value Varchar(8000))
AS
BEGIN
–First Test the data is of type Varchar.
IF(dbo.ValidateExpectedType(103, @Data)<>1) RETURN

–Loop thru the list inserting each
– item into the variable table.
DECLARE @Ptr int, @Length int,
@VarcharLength smallint, @Value Varchar(8000)
SELECT @Length = DataLength(@Data), @Ptr = 2
WHILE(@Ptr<@Length)
BEGIN
–The first 2 bytes of each item is the length of the
–varchar, a negative number designates a null value.
SET @VarcharLength = SUBSTRING(@Data, @ptr, 2)
SET @Ptr = @Ptr + 2
IF(@VarcharLength<0)
SET @Value = NULL
ELSE
BEGIN
SET @Value = SUBSTRING(@Data, @ptr, @VarcharLength)
SET @Ptr = @Ptr + @VarcharLength
END
INSERT INTO @DataTable (Value) VALUES(@Value)
END
RETURN
END

من همچنین تعدادی کلاس C# برای ایجاد آرایه هایی از نوع بایت از نوع داده های مختلف ایجاد کرده ام .

توجه : کد هایی که در ادامه می آید بخشی از یک برنامه برای مزرعه پرورش صدف می باشد .

در این مثال برای فراخوانی پایگاه داده از کلاس SQLHelper که یکی از بلاک های برنامه مایکروسافت می باشد استفاده کرده ام . شما می توانید این بلاک برنامه را در MSDN مشاهده کنید. فرستادن یک لیست از شناسه های integer برای انتخاب رکوردهای مربوطه در متد زیر اقلام چک شده ی یک لیست باکس را گرفته و شناسه های آنها را به یک Stored Procedure می فرستیم . Stored Procedure سپس یک مجموعه از نتایج را که شامل جزییات هر شناسه انتخاب شده می باشد را بر می گرداند .

private DataSet GetSelectedSnailDetails()
{
SQLIntListCreator snailIDs = new SQLIntListCreator();
foreach(Snail aSnail in mySelectionCheckedListBox.CheckedItems)
snailIDs.AddValue(aSnail.SnailID);

return SQLHelper.ExecuteDataset(CONN_STRING,
“GetSnailDetails”, snailIDs.GetList());
}

از Stored Procedure زیر برای گرفتن لیستی از نوع داده int که به فرم image ( آرایه ای از بایت) می باشد ؛ استفاده می شود . این روال لیست را به جدول متغیری از نوع int تبدیل می کند سپس این جدول را به ستون SnailID از جدول Snails متصل می نماید ، تا بتواند جزییات را برای هر صدف انتخاب شده برگرداند .

CREATE PROCEDURE GetSnailDetails
@SnailIDs image
AS
SELECT Snail.*
FROM dbo.GetTableInt(@SnailIDs) SIDs
INNER JOIN Snails ON SIDs.Value = Snails.SnailID
GO

روال ذخیره شده برای حذف همه صدف ها در لیست @Snails از نوع image به فرم زیر می باشد .

CREATE PROCEDURE DeleteSnails
@SnailIDs image
AS
DELETE Snail
FROM dbo.GetTableInt(@SnailIDs) SIDs
INNER JOIN Snails ON SIDs.Value = Snails.SnailID
GO

متد فرستادن مجموعه ای از حالات صدف به Stored Procedure برای بهنگام سازی به فرم زیر می باشد .

private void UpdateSnailStatuses(Snail[] snails)
{
SQLIntListCreator snailIDs = new SQLIntListCreator();
SQLVarcharListCreator statuses =
new SQLVarcharListCreator();
SQLRowversionListCreator rowVersions =
new SQLRowversionListCreator();

foreach (Snail aSnail in snails)
{
snailIDs.AddValue(aSnail.SnailID);
statuses.AddValue(aSnail.Status);
rowVersions.AddValue(aSnail.RowVersion);
}

SQLHelper.ExecuteNonquery(CONN_STRING,
“UpdateSnailStatuses”, snailIDs.GetList(),
statuses.GetList(), rowVersions.GetList());
}

از روال زیر نیز برای بهنگام سازی حالات صدف ها استفاده می شود .

CREATE PROCEDURE dbo.UpdateSnailStatuses
@SnailIDs image,
@Statuses image,
@RowVersions image
AS
UPDATE Snail
SET Snail.Status = Statuses.Value
FROM Snail
INNER JOIN GetTableInt(@SnailIDs) SnailIDs
ON Snail.SnailID = SnailIDs.Value
INNER JOIN GetTableVarchar(@Statuses) Statuses
ON SnailIDs.RowID = Statuses.RowID
INNER JOIN GetTableRowversion(@RowVersions) RowVersions
ON Statuses.RowID = RowVersions.RowID
WHERE TSEQUAL(Snail.RowVersion, RowVersions.Value)

RETURN @@ERROR

فرستادن یک DataTable به یک Stored Procedure برای درج در یک جدول

از کد زیر برای تبدیل داده های یک DataTable به پنج آرایه از نوع بایت استفاده می شود . این آرایه ها سپس به Stored Procedure ی AddSnails برای درج در جدول Snail فرستاده می شوند .

private void AddSnails(DataTable snails)
{
SQLVarcharListCreator species = new SQLVarcharListCreator();
SQLDatetimeListCreator dOB = new SQLDatetimeListCreator();
SQLNvarcharListCreator location = new SQLNvarcharListCreator();
SQLBitListCreator isMale = new SQLBitListCreator();
SQLMoneyListCreator value = new SQLMoneyListCreator();

foreach(DataRow row in snails.Rows)
{
species.AddValue(row["Species"]);
dOB.AddValue(row["DOB"]);
location.AddValue(row["Location"]);
isMale.AddValue(row["IsMale"]);
value.AddValue(row["Value"]);
}

// A command is explicitly created here
// instead of using SQLHelper as we need to be
// able to set the CommandTimeout property
// big enough to insert 1 000 000 records.
using (SqlConnection cnn = new SqlConnection(CONN_STRING))
{
cnn.Open();
SqlCommand comInst = new SqlCommand(“AddSnails”, cnn);
comInst.CommandType = CommandType.StoredProcedure;
comInst.CommandTimeout = 10000;

comInst.Parameters.Add(“@Species”, species.GetListAndReset());
comInst.Parameters.Add(“@DOB”, dOB.GetListAndReset());
comInst.Parameters.Add(“@Location”, location.GetListAndReset());
comInst.Parameters.Add(“@IsMale”, isMale.GetListAndReset());
comInst.Parameters.Add(“@Value”, value.GetListAndReset());
comInst.ExecuteNonQuery();
}
}

و از Stored Procedure زیر برای تبدیل تصویر به جدول متغیرها و اتصال آنها به هم و درج داده های حاصله در جدول Snail استفاده می شود .

ALTER PROCEDURE dbo.AddSnails
(
@Species image,
@DOB image,
@Location image,
@IsMale image,
@Value image
)
AS
INSERT INTO Snail (Species, DOB, Location, IsMale, Value)
SELECT Species.Value, DOB.Value,
Location.Value, IsMale.Value, Value.Value
FROM GetTableMoney(@value) Value
INNER JOIN GetTableBit(@isMale) IsMale ON Value.RowID = IsMale.RowID
INNER JOIN GetTableVarchar(@species) Species
ON IsMale.RowID = Species.RowID
INNER JOIN GetTableDateTime(@dOB) DOB ON Species.RowID = DOB.RowID
INNER JOIN GetTableNvarchar(@location) Location
ON DOB.RowID = Location.RowID

RETURN @@ERROR

تصویر زیر اتصال همه جداول متغیر ها را نشان می دهد .

کارایی استفاده از این روش

برای مقایسه سرعت درج با استفاده از روش گفته شده در بالا (و بیان کارایی آن) با روش استاندارد وارد کردن یکی یکی رکورد ها به پایگاه داده ها مقایسه زیر با استفاده از یک کامپیوتر پنتیوم ۴ همراه با ۵۱۲ مگا بایت حافظه رم انجام شده است .در این مقایسه بخش کلاینت و سرور هر دو بر روی یک ماشین قرار داشته است . و در صورتیکه بخواهیم این آزمایش را بر روی یک شبکه سریع انجام دهیم زمان به مراتب کمتری خواهد داشت .

Records Inserted

Standard one stored procedure call per record (msec)

One stored procedure call for all records (msec)

1

2

10

10

22

14

100

219

60

1000

2 259

505

10 000

22 593

4 083

100 000

301 368

44 645

1 000 000

3 094 385

571 020

دیدگاه خود را بیان کنید.

باید وارد سایت شده باشید برای دیدگاه دادن