有没有一种方法可以创建新表类型并传递数据表,而无需执行任何过程?

时间:2019-04-30 14:43:27

标签: c# sql-server

我正在Windows环境和Visual Studio 2017中使用C#和SQL Server。我试图将数据表(称为@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 :(得分:0)

关键点是将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;
        }

    }
}