【问题标题】:Is there a way to create a new table type and pass a data-table without a procedure?有没有办法创建一个新的表类型并在没有过程的情况下传递一个数据表?
【发布时间】:2019-05-01 03:04:22
【问题描述】:

我在带有 Visual Studio 2017 的 Windows 环境中使用 C# 和 SQL Server。我正在尝试将数据表(称为 @profiles)传递给 SQL 脚本。

为此,我首先必须创建一个与传递的数据表匹配的表类型。

问题是,在我尝试使用传递的数据表填充一个新表时,我遇到了两个异常之一:

  1. “列、参数或变量@profiles。: 找不到数据类型 ProfileIdTableType。”

  2. “表类型参数'@profiles'必须有一个有效的类型名称。”

根据我的搜索,我可以发现具有新表类型的数据表通常与过程一起使用,但无论如何 - 我仍然遇到上述异常。

我试图声明一个新的表类型并使用@profiles,但没有成功。

当我声明我用来传递的SqlParameter时,我一般会遇到第一个异常(找不到类型)

我应该提一下,我在 SQL Server 的“可编程性”部分中找不到创建的类型(但我的类型是 temp,所以应该是)

这是我用来将数据表从 C# 传递到脚本的 2 种方法:

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、微软文档和网络。

如果有任何我遗漏的重要信息,请告诉我。

非常感谢一些建议。

干杯!

【问题讨论】:

  • 使用表参数时使用System.Data.SqlDbType.Structured 作为SqlDbType
  • 可以添加存储过程的代码PopulateTable吗?

标签: c# sql-server


【解决方案1】:

关键是把SqlDbType指定为Structured plus来定义TypeName如下sn-p所示。

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

    }
}

【讨论】:

  • 我可以在代码中(在使用@profiles 之前)创建我想要的 UDDT 表吗? - 含义:代替此: // EMAIL.TVP_Emails 应该存在于您的 SQL 实例中,UDDT 类型 comm.Parameters[comm.Parameters.Count - 1].TypeName = "EMAIL.TVP_Emails";在代码中创建这种 UDDT 表,例如:CREATE TYPE ProfileIdTableType AS TABLE (ID INT) go 然后以某种方式使用@profiles??
  • 我是否有可能无法开始新行? ;)
  • 是的,这只是 DDL 语句。在发出 DDL 语句之前确保 UDDT 不存在。并确保用户帐户具有执行 DDL 语句的适当权限。一切都可以使用相同的 Net cmd 在一批中完成。只需在 DML 之前插入 DDL 语句。我不确定你的第二条评论是什么意思。
猜你喜欢
  • 2020-01-28
  • 1970-01-01
  • 2019-07-02
  • 2017-07-16
  • 1970-01-01
  • 1970-01-01
  • 2012-07-25
  • 2011-12-20
  • 2020-12-20
相关资源
最近更新 更多