Soru Tablo değeri parametresi nasıl iletilir?


Saklı bir yordam için bir tablo değeri parametresi geçirmeye çalışıyorum, ancak bir istisna almaya devam ediyorum (aşağıya bakın).

SqlCommand c = new SqlCommand("getPermittedUsers", myConn) { CommandType = CommandType.StoredProcedure };

c.Parameters.AddWithValue("@intNotifyingUserId", notifyingUserId);
c.Parameters.AddWithValue("@tSelectedPdfIds", sharedPdfs).SqlDbType = SqlDbType.Structured;

SqlDataReader dr = c.ExecuteReader();

Tip, sunucuda şöyle tanımlanır:

CREATE TYPE [dbo].[IdList] AS TABLE(
    [Id] [int] NOT NULL
)

SharedPdfs'yi bir List<int>, ve IQueryable<int>ancak aşağıdaki istisnaları almaya devam edin:

Object must implement IConvertible.

Neyi yanlış yaptığımı bilen var mı? Belgeler, bir listeyi TVP olarak geçirebileceğimi, ancak herhangi bir örnek vermediğimi ima ediyor.

Teşekkür ederim.


32
2017-08-08 22:50


Menşei


Nasıl getPermittedUsers beyan? - Marcelo Cantos
Bu uzun bir atış, ama geçmeyi denediniz mi int[]? - Marcelo Cantos
Kullanmalısın DataTable. - ChaosPandion
Teşekkürler, bir ile çalıştı DataTable. Yine de IQueryable'ımı DataTable'a dönüştürmek zorunda kalmak sıkıcı. - nw.
IEnumerable <SqlDataRecord> öğesini de uygulayabilirsiniz. lennilobel.wordpress.com/2009/07/29/... - Derek Beattie


Cevaplar:


Parametreyi bir DataTable, IEnumerable<SqlDataRecord>veya DbDataReader.


12
2017-09-16 16:57



? SQLCommand'a emin misin? - Davide Piras
Evet, SqlCommand'daki bir Tablo Değeri Parametresi için desteklenen türlerdir. Bütün belgeler burada: msdn.microsoft.com/en-us/library/bb675163.aspx . Aşağı yolun 1 / 3'üne bakın: "System.Data.SqlClient, tablo değerli parametreleri DataTable, DbDataReader veya System.Collections.Generic.IEnumerable <SqlDataRecord> ([T: System.Collections.Generic.IEnumerable`1) doldurma destekler. nesneler. - Jared Moore
bu da Oracle'da mümkün mü? - Mr.
Tablo Değerli Parametreler bir SQL Server özelliğidir. Oracle'ın kendi benzeri bir özelliği olabilir veya olmayabilir, bilmiyorum. - Jared Moore
@Bay. Hayır ama UDT ve ntypes kontrol edin. Bir UDT bir sınıfa benzer, bir toplama / liste için bir ntype. Bu mekanizmayı kullanarak .net ve veritabanı arasında çok karmaşık nesneler geçtim. ODP.net'i kullanmanız gerekiyor ve UDT'lere destek olarak hangi versiyonun sadece nispeten yakın zamanda ekleneceğinin farkında olmanız gerekiyor. - PeteH


Aşağıdaki örnek, ya DataTable ya da IEnumerable<SqlDataRecord>:

SQL Kodu

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

C # Kodu

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;
    }
}

44
2018-05-28 05:07



Bu bana yardımcı oldu, teşekkürler! - s0nica
üzerinde bulduğum şeyden çalışmayı deniyordum. sqlperformance.com/2012/08/t-sql-queries/... ama dbnull değerleri almaya devam etti. Örneğiniz benim için çalışmaya son verdi, parametre.typename olabilir. Teşekkürler! - Phil
Not: Bunun için özel bir tür oluşturmak istemeyenler için, bir geçici veri, verileri bir xml türü olarak iletmek ve sonra buna karşı sorgulamaktır. - JohnLBevan