। নেট কোড থেকে সঞ্চিত পদ্ধতিতে সারণী মানের পরামিতিগুলি কীভাবে পাস করবেন


171

আমার একটি এসকিউএল সার্ভার 2005 ডাটাবেস রয়েছে। কয়েকটি পদ্ধতিতে আমার টেবিলের প্যারামিটার রয়েছে যা আমি একটি স্টোরকৃত প্রোকে পাস করি nvarchar(কমা দ্বারা আলাদা) এবং অভ্যন্তরীণভাবে একক মানগুলিতে বিভক্ত। আমি এটিকে এসকিউএল কমান্ড প্যারামিটারগুলির তালিকায় যুক্ত করব:

cmd.Parameters.Add("@Logins", SqlDbType.NVarchar).Value = "jim18,jenny1975,cosmo";

আমাকে ডাটাবেসটি এসকিউএল সার্ভার ২০০ 2008-এ স্থানান্তর করতে হবে। আমি জানি যে টেবিলের মান প্যারামিটার রয়েছে এবং আমি জানি কীভাবে সেগুলি সঞ্চিত পদ্ধতিতে ব্যবহার করতে হয়। তবে আমি জানি না কীভাবে একটি এসকিউএল কমান্ডের প্যারামিটার তালিকায় একটি পাস করতে হয়।

Parameters.Addপদ্ধতিটির সঠিক বাক্য গঠন কি কেউ জানেন ? বা এই প্যারামিটারটি পাস করার অন্য কোনও উপায় আছে?


এই সমাধানটি দেখুন: EF- এ টেবিলের মূল্যবান প্যারামিটার সহ সঞ্চিত পদ্ধতি। কোড.msdn.microsoft.com/Stored-Procedure-with-6c194514
কার্ল প্রথমম্যান

এর মতো একটি ক্ষেত্রে, আমি সাধারণত স্ট্রিংগুলি সংক্ষিপ্ত করে সেগুলি সার্ভারের দিকে বিভক্ত করি বা আমার একাধিক কলাম থাকে তবে একটি এক্সএমএলও পাস করি। এক্সএমএল প্রক্রিয়াকরণ করার সময় এটি খুব দ্রুত স্কেল। আপনি সমস্ত পদ্ধতি ব্যবহার করে প্রসেসিংয়ের সময় যাচাই করতে পারেন এবং এর পরে সেরা পদ্ধতিটি বেছে নিতে পারেন। একটি এক্সএমএল দেখতে <আইটেম> <আইটেম মান = "সাদাদাস" /> <আইটেম মান = "সাদসাদ" /> ... </ i> SQL সার্ভারে প্রক্রিয়াটিও সহজ simple এই পদ্ধতিটি ব্যবহার করে, আপনার যদি আরও তথ্যের প্রয়োজন হয় তবে আপনি সর্বদা <item> এ একটি নতুন বৈশিষ্ট্য যুক্ত করতে পারেন।
নিনু আলেকজান্দ্রু

4
@ নিনু অ্যালেক্সান্দ্রু, "এক্সএমএল প্রসেস করার সময় এটি এসকিউএল খুব দ্রুত।" কাছেও নয়।
nothrow

উত্তর:


279

DataTable, DbDataReaderবা IEnumerable<SqlDataRecord>বস্তুগুলি এসকিউএল সার্ভার ২০০৮ (ADO.NET) এর এমএসডিএন নিবন্ধ অনুযায়ী সারণী-মূল্যবান পরামিতিগুলি প্রতি টেবিল-মূল্যবান প্যারামিটার তৈরি করতে ব্যবহৃত হতে পারে ।

নিম্নলিখিত উদাহরণটি একটি DataTableবা একটি ব্যবহার করে চিত্রিত করে IEnumerable<SqlDataRecord>:

এসকিউএল কোড :

CREATE TABLE dbo.PageView
(
    PageViewID BIGINT NOT NULL CONSTRAINT pkPageView PRIMARY KEY CLUSTERED,
    PageViewCount BIGINT NOT NULL
);
CREATE TYPE dbo.PageViewTableType AS TABLE
(
    PageViewID BIGINT NOT NULL
);
CREATE PROCEDURE dbo.procMergePageView
    @Display dbo.PageViewTableType READONLY
AS
BEGIN
    MERGE INTO dbo.PageView AS T
    USING @Display AS S
    ON T.PageViewID = S.PageViewID
    WHEN MATCHED THEN UPDATE SET T.PageViewCount = T.PageViewCount + 1
    WHEN NOT MATCHED THEN INSERT VALUES(S.PageViewID, 1);
END

সি # কোড :

private static void ExecuteProcedure(bool useDataTable, 
                                     string connectionString, 
                                     IEnumerable<long> ids) 
{
    using (SqlConnection connection = new SqlConnection(connectionString)) 
    {
        connection.Open();
        using (SqlCommand command = connection.CreateCommand()) 
        {
            command.CommandText = "dbo.procMergePageView";
            command.CommandType = CommandType.StoredProcedure;

            SqlParameter parameter;
            if (useDataTable) {
                parameter = command.Parameters
                              .AddWithValue("@Display", CreateDataTable(ids));
            }
            else 
            {
                parameter = command.Parameters
                              .AddWithValue("@Display", CreateSqlDataRecords(ids));
            }
            parameter.SqlDbType = SqlDbType.Structured;
            parameter.TypeName = "dbo.PageViewTableType";

            command.ExecuteNonQuery();
        }
    }
}

private static DataTable CreateDataTable(IEnumerable<long> ids) 
{
    DataTable table = new DataTable();
    table.Columns.Add("ID", typeof(long));
    foreach (long id in ids) 
    {
        table.Rows.Add(id);
    }
    return table;
}

private static IEnumerable<SqlDataRecord> CreateSqlDataRecords(IEnumerable<long> ids) 
{
    SqlMetaData[] metaData = new SqlMetaData[1];
    metaData[0] = new SqlMetaData("ID", SqlDbType.BigInt);
    SqlDataRecord record = new SqlDataRecord(metaData);
    foreach (long id in ids) 
    {
        record.SetInt64(0, id);
        yield return record;
    }
}

24
+1 দুর্দান্ত উদাহরণ। Takeaways: a পাঠাতে DataTableপ্যারামিটার মান সেট যেমন SqlDbTypeকরতে Structuredএবং TypeNameডাটাবেসের UDT নাম।
এলসি

10
আপনি যদি কোনও লুপে কোনও রেফারেন্স টাইপের উদাহরণ পুনরায় ব্যবহার করতে চলেছেন (আপনার উদাহরণে স্কেলডাটা রেকর্ড), দয়া করে দয়া করে এই বিশেষ পরিস্থিতিতে কেন এটি নিরাপদ তা সম্পর্কে একটি মন্তব্য যুক্ত করুন।
সেরেন বোইসেন

2
এই কোডটি ভুল: খালি টেবিলের মূল্যবান প্যারামিটারগুলির মান সেট করা উচিত null। খালি প্যারামিটার দেওয়া থাকলে CreateSqlDataRecordsআর ফিরে আসবে না । nullids
ta.speot.is

4
@ ক্রোনো: DataTable(বা DataSet) কেবলমাত্র এটি প্রয়োগ করে কারণ তাদের ভিজ্যুয়াল-স্টুডিওতে টেনে আনার এবং ছাড়ার ক্ষমতা সরবরাহ করতে হবে, সুতরাং তারা IComponentকোন প্রয়োগগুলি বাস্তবায়ন করে IDisposable। আপনি যদি ডিজাইনার ব্যবহার না করেন তবে এটি ম্যানুয়ালি তৈরি করেন তবে এটিকে নিষ্পত্তি করার কোনও কারণ নেই (বা usingস্টেটমেন্ট ব্যবহার করার জন্য )। সুতরাং এটি স্বর্ণের নিয়মের ব্যতিক্রমগুলির মধ্যে একটি "প্রয়োগকারী সমস্ত কিছু নিষ্পত্তি করুন IDisposable"।
টিম শ্মেলটার

2
@ টিমস্মেলটার থাম্বের নিয়ম হিসাবে আমি সর্বদা Disposeপদ্ধতিগুলিকে কল করি , এমনকি যদি এটি কেবলমাত্র কোড অ্যানালাইসিস আমাকে সতর্ক না করে তবে আমি তা না করি। তবে আমি সম্মত হই যে এই নির্দিষ্ট দৃশ্যে যেখানে বেস DataSetএবং DataTableদৃষ্টান্তগুলি ব্যবহৃত হয়, কল করা Disposeকিছুই করবে না।
ক্রোনো

31

রায়ান এর উত্তর আরও আপনার কাছে সেট করতে হবে DataColumnএর Ordinalসম্পত্তি আপনি একটি সাথে ডিল করা হয় table-valued parameterসঙ্গে একাধিক কলাম যার ordinals হয় না বর্ণানুসারে।

উদাহরণস্বরূপ, যদি আপনার নিম্নলিখিত টেবিলের মান থাকে যা এসকিউএলে একটি প্যারামিটার হিসাবে ব্যবহৃত হয়:

CREATE TYPE NodeFilter AS TABLE (
  ID int not null
  Code nvarchar(10) not null,
);

আপনার নিজের কলামগুলিকে সি # তে অর্ডার করতে হবে:

table.Columns["ID"].SetOrdinal(0);
// this also bumps Code to ordinal of 1
// if you have more than 2 cols then you would need to set more ordinals

আপনি যদি এটি করতে ব্যর্থ হন তবে আপনি একটি পার্স ত্রুটি পাবেন, এনভারচচারকে ইনটে রূপান্তর করতে ব্যর্থ হন।


15

জাতিবাচক

   public static DataTable ToTableValuedParameter<T, TProperty>(this IEnumerable<T> list, Func<T, TProperty> selector)
    {
        var tbl = new DataTable();
        tbl.Columns.Add("Id", typeof(T));

        foreach (var item in list)
        {
            tbl.Rows.Add(selector.Invoke(item));

        }

        return tbl;

    }

আপনি কি দয়া করে আমাকে জানান যে আমি প্যারামিটার হিসাবে কী পাস করব? ফানক <টি, টিপ্রোপার্টি> নির্বাচক? এটি কেবল tbl.Rows.Ad (আইটেম) এবং প্যারামিটারের কোনও প্রয়োজন হতে পারে না।
জিড্রয়েড

নির্বাচক.আরভোক (আইটেম) আইটেমের সম্পত্তিটি বেশিরভাগ ক্ষেত্রে তার কোনও পূর্ববর্তী ক্ষেত্রে নির্বাচন করে, তবে এটি আপনাকে একটি স্ট্রিং সম্পত্তিও নির্বাচন করতে দেয়
মার্টিয়া

আমি কীভাবে সেখানে নির্বাচককে রাখি তার একটি উদাহরণ প্রদান করতে পারেন ?? সঞ্চিত প্রকল্পে পাস করার জন্য আমার কাছে <গুইড> একটি তালিকা রয়েছে ...
জিড্রয়েড

গাইডলাইস্ট. টুটেবলভ্যালিউডপ্যারামিটার (x => এক্স), যেহেতু এক্স আপনার ক্ষেত্রে
নির্দেশিকা

5

এটির সাথে কাজ করার সর্বোত্তম উপায়। আপনার টেবিলটি ধরে নেওয়া হচ্ছে "dbo.tvp_Int" নামে পরিচিত পূর্ণসংখ্যার একটি তালিকা (আপনার নিজের টেবিলের প্রকারের জন্য কাস্টমাইজ করুন)

এই এক্সটেনশন পদ্ধতিটি তৈরি করুন ...

public static void AddWithValue_Tvp_Int(this SqlParameterCollection paramCollection, string parameterName, List<int> data)
{
   if(paramCollection != null)
   {
       var p = paramCollection.Add(parameterName, SqlDbType.Structured);
       p.TypeName = "dbo.tvp_Int";
       DataTable _dt = new DataTable() {Columns = {"Value"}};
       data.ForEach(value => _dt.Rows.Add(value));
       p.Value = _dt;
   }
}

এখন আপনি যে কোনও জায়গায় এক লাইনে কোনও টেবিলের মূল্যবান প্যারামিটার যুক্ত করতে পারেন:

cmd.Parameters.AddWithValueFor_Tvp_Int("@IDValues", listOfIds);

1
যদি পরামিতি সংগ্রহটি নুল হয়? খালি টাইপ কিভাবে পাস করবেন?
মুফ্লিক্স

2
@ মুফ্লিক্স অস্পষ্টভাবে, এক্সটেনশন পদ্ধতিগুলি নাল দৃষ্টান্তের বিরুদ্ধে কাজ করে। সুতরাং if(paramCollection != null)পদ্ধতির শীর্ষে একটি সাধারণ চেক যুক্ত করা ভাল হবে
রোম্বারল

1
প্রাথমিক-চেক-সহ আপডেট উত্তর
শাহজাদ কুরেশি

2
কিছুটা পেডেন্টিক হতে পারে, তবে আমি স্বাক্ষরের IEnumerableপরিবর্তে ব্যবহার করতাম List, আপনি IEnumerableকেবল কোনও তালিকাই নয়, যা কিছু নির্দিষ্ট করতে Listপারেন তা যেহেতু আপনি নির্দিষ্ট কোনও ফাংশন ব্যবহার করছেন না , তাই আমি সত্যিই কোন কারণ দেখছি না আমাদেরIEnumerable
ফ্রান্সিস লর্ড

তালিকা ব্যবহার করা আপনাকে শর্টহ্যান্ড ডেটা ব্যবহারের অনুমতি দেয় For forEach (), অন্যথায় আপনাকে আসলে একটি foreach লুপ লিখতে হবে। যা কাজ করতে পারে তবে আমি যতটা সম্ভব সংক্ষিপ্ত জিনিস লিখতে পছন্দ করি।
শাহজাদ কুরেশি

0

আপনার ধরণ থেকে উপযুক্ত পরামিতি তৈরি করতে এই কোডটি ব্যবহার করুন:

private SqlParameter GenerateTypedParameter(string name, object typedParameter)
{
    DataTable dt = new DataTable();

    var properties = typedParameter.GetType().GetProperties().ToList();
    properties.ForEach(p =>
    {
        dt.Columns.Add(p.Name, Nullable.GetUnderlyingType(p.PropertyType) ?? p.PropertyType);
    });
    var row = dt.NewRow();
    properties.ForEach(p => { row[p.Name] = (p.GetValue(typedParameter) ?? DBNull.Value); });
    dt.Rows.Add(row);

    return new SqlParameter
    {
        Direction = ParameterDirection.Input,
        ParameterName = name,
        Value = dt,
        SqlDbType = SqlDbType.Structured
    };
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.