Есть ли способ создать новый тип таблицы и передать таблицу данных без процедуры? - PullRequest
1 голос
/ 30 апреля 2019

Я использую C # и SQL Server в среде Windows с Visual Studio 2017. Я пытаюсь передать таблицу данных (называемую @profiles) в сценарий SQL.

Чтобы сделать это, я сначала должен создать тип таблицы, которая соответствует таблице данных, переданной.

Проблема заключается в том, что во всех случаях, когда я пытался заполнить новую таблицу пропущенными данными, я получаю одно из двух исключений:

  1. "Столбец, параметр или переменная @profiles.: Не удается найти тип данных ProfileIdTableType."

  2. "Параметр типа таблицы '@profiles' должен иметь правильное имя типа."

Из того, что я искал, я обнаружил, что таблица данных с новым типом таблицы обычно используется с процедурой, но неважно - я все еще получаю вышеупомянутые исключения.

Я попытался объявить новый тип таблицы и использовать @profiles с ним безуспешно.

Когда я объявляю SqlParameter, который я использую для его передачи, я обычно сталкиваюсь с первым исключением (не могу найти тип)

Я должен упомянуть, что не могу найти созданный тип в разделе «Программируемость» SQL Server (но у меня тип temp и так и должно быть)

Это два способа передачи данных в сценарий из C #:

SqlParameter @profiles = new SqlParameter("@profiles", profileIds.Tables[0]);
profiles.TypeName = "ProfileIdTableType";

или

DbParameter @profiles = new SqlParameter("@profiles", profileIds.Tables[0]);

и затем используйте его:

updatedProfiles = (int)DbAdminOps.ExecuteNonQueryCommand(updateProfileSettingsCommand, CommandType.Text, new DbParameter[] { @profiles, @updatedTemplate }, null);

Это SQL-скрипт, который я использовал в последний раз (но перепробовал множество вариантов, не представленных здесь)

    -- create a table type of profile Ids passed by user
    CREATE TYPE ProfileIdTableType AS TABLE (ID INT)
    go

    DECLARE @PRFL ProfileIdTableType
    GO

    CREATE PROCEDURE PopulateTable
        @profiles ProfileIdTableType READONLY
    AS 
        INSERT INTO @PRFL(ID) 
            SELECT [ID] FROM @profiles
    GO

    @profiles ProfileIdTableType
    EXEC PopulateTable @profiles
    go

Я ожидал, что @profiles будет распознан как таблица, поэтому я могу использовать ее в своем сценарии, но все, что я получаю, - это исключение. Я приложил много усилий, но не смог.

Прошел все вопросы о переполнении стека, YouTube, документацию Microsoft и веб.

Если есть какая-то информация, которую я пропустил и которая важна - дайте мне знать.

Был бы очень признателен за совет.

Ура!

1 Ответ

0 голосов
/ 30 апреля 2019

Ключевым моментом является указание SqlDbType как структурированного плюс для определения TypeName, как показано в следующем фрагменте.

    comm.Parameters.AddWithValue("@tvpEmails", dt);
// EMAIL.TVP_Emails should exist on your SQL instance under UDDT types
     comm.Parameters[comm.Parameters.Count - 1].TypeName = "EMAIL.TVP_Emails";
     comm.Parameters[comm.Parameters.Count - 1].SqlDbType = SqlDbType.Structured;

См. Полный код ниже.Пожалуйста, дайте мне знать, если у вас возникнут трудности.

using System.Data;
using System.Data.SqlClient;
using System.Net.Mail;

namespace ConsoleApp10
{
    class Program
    {
        static void Main(string[] args)
        {
            var mm = new MailMessage();
            using (var conn = new SqlConnection("your connection string"))
            {
                using (var comm = new SqlCommand())
                {

                    comm.Connection = conn;
                    conn.Open();


                    comm.CommandText =
                        @"INSERT INTO [EMail].[MailAttachments] (fileName,fileSize,attachment)
                                             SELECT fileName, fileSize, attachment FROM @tvpEmails";


                    var dt = CreateTable();
                    foreach (var eml in mm.Attachments)
                    {
                        var newRow = dt.NewRow();
                        newRow["FileName"] = eml.Name;
                        newRow["FileSize"] = eml.ContentStream.Length;
                        var allBytes = new byte[eml.ContentStream.Length];
                        newRow["Attachment"] = allBytes;
                        eml.ContentStream.Position = 0;
                        dt.Rows.Add(newRow);
                    }

                    comm.Parameters.AddWithValue("@tvpEmails", dt);
                    comm.Parameters[comm.Parameters.Count - 1].TypeName = "EMAIL.TVP_Emails";
                    comm.Parameters[comm.Parameters.Count - 1].SqlDbType = SqlDbType.Structured;
                    comm.ExecuteNonQuery();
                    if (conn.State == ConnectionState.Open)
                        conn.Close();
                }

            }

        }
        private static DataTable CreateTable()
        {
            var dt = new DataTable();
            dt.Columns.Add("FileName", typeof(string));
            dt.Columns.Add("FileSize", typeof(long));
            dt.Columns.Add("Attachment", typeof(byte[]));
            return dt;
        }

    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...