c# - 如何匹配 UDT T-SQL 和 C# CLR 类型?

标签 c# sql sql-server clr sqlclr

不确定这个问题是否有意义,但我是 CLR/UDT 的新手,刚刚完成了这里的示例: https://learn.microsoft.com/en-us/sql/relational-databases/clr-integration/database-objects/getting-started-with-clr-integration?view=sql-server-2017

我现在想要实现的目标非常相似。我已经尝试添加一个字符串参数而没有失败,但是当添加 C# 对象时问题就开始了。

这是我的 C# 主程序:

[Microsoft.SqlServer.Server.SqlProcedure]
public static void HelloName(Person person, [param: SqlFacet(MaxSize=-1)]out string result)
{
    SqlContext.Pipe.Send("Hello world!" + Environment.NewLine);
    result = "Hello, " + person.firstName + " " + person.lastName;
}

这是 C# Person 类:

    public class Person
    {
        public string firstName;
        public string lastName;
        public Person(string firstName, string lastName)
        {
            this.firstName = firstName;
            this.lastName = lastName;
        }
    }

我能够成功创建程序集,但这是我卡住的过程。我想做类似的事情:

CREATE PROCEDURE helloname
(
    @person (@firstname nchar(300), @lastname nchar(300))
    @result nchar(300) OUTPUT
 )
AS EXTERNAL NAME helloworld.HelloWorldProc.HelloName

但经过一些研究后,显然处理对象的最佳方法是通过 UDT。我按照另一个示例在 T-SQL 中创建了一个 Person 表和一个 PersonType,如下所示:

CREATE TABLE Person  
(  
    FirstName nvarchar(50),  
    LastName nvarchar(50)  
)  
Go  

CREATE TYPE PersonType AS TABLE  
(  
    FirstName nvarchar(50),  
    LastName nvarchar(50)  
)  
Go  

错误发生在这里:

CREATE PROCEDURE helloname
(
    @personType PersonType,
    @result nchar(300) OUTPUT
)
AS EXTERNAL NAME helloworld.HelloWorldProc.HelloName

在尝试执行时,它说“为“helloname”创建过程失败,因为参数“@personType”的 T-SQL 和 CLR 类型不匹配。”

如何让“PersonType”等于 C# 类“Person”才能使其正常工作?让我知道我是否以完全错误的方式解决这个问题/如果有更简单的解决方案。理想情况下,我将在 Person 中传递一个具有多个变量类型的列表。提前致谢。

最佳答案

我认为您误解了用户定义类型的概念。这些与用户定义的数据类型(将随机名称映射到实际的 T-SQL 数据类型)或用户定义的表类型(用于创建表变量的预定义表模式,通常用作表值参数)不同。

试试这个以获得更好的介绍:CLR User-Defined Types

Let me know if I'm going about this the completely wrong way/if there's a simpler solution. Ideally I will be passing in a List with multiple variable types inside Person.

如果存储过程将成为 T-SQL 存储过程,那么最好的方法是使用用户定义的表类型/TVP(即 CREATE TYPE PersonType AS TABLE... )。但由于 SQLCLR 不接受 TVP,您可以执行以下任一操作:

  • 将复杂“对象”的列表构建为 XML 文档,该文档很容易在 .NET 中进行解析。使用 SqlXml 作为 .NET 输入参数类型。
  • 创建一个本地临时表(即从单个 # 开始),填充它,然后使用 Context Connection = true 作为 SQLCLR 存储过程从中读取它连接字符串。我不确定在什么情况下此选项会比简单地传入 XML 文档更好/更容易,但它仍然是一个选项。

其他说明:

  1. 您不需要 SqlFacet 属性的 param: 部分。
  2. 使用 SqlString 作为传入数据类型,而不是 string。通过 ParamName.Value 属性获取 .NET 字符串。通过 ParamName.IsNull 属性检查 NULL
  3. 参数不能表示为参数的组合。意思是,@person (@firstname nchar(300), @lastname nchar(300)) 在任何情况下都不是有效语法。

有关一般使用 SQLCLR 的更多信息,请访问:SQLCLR Info

关于c# - 如何匹配 UDT T-SQL 和 C# CLR 类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53401082/

相关文章:

c# - 如何将 "path"传递给 C# 中的对象成员?

sql - 代理作业历史记录保存在 SQL Server 中的什么位置?

php - 使用 2 个 LEFT JOINS 查询多个 LIKE

SQL将数据插入临时表,拆分列

sql-server - T SQL 如果列存在则(如果它有值 X 那么(

sql-server - 使用特定单词搜索表列

c# - 如何重构所需的 else 子句?

c# - 启动协程统一给出空引用异常

c# - 引发事件时要调用的注册方法的方法

asp.net - 创建一个新的 Orchard 站点