Как сопоставить типы UDT T-SQL и C# CLR?

Не уверен, что этот вопрос имеет смысл, но я новичок в CLR/UDT и только что закончил следовать этому примеру здесь: https://docs.microsoft.com/en-us/sql/relational-databases/clr-integration/database-objects/getting-start-with-clr-integration?view=sql-server-2017

То, чего я хочу достичь прямо сейчас, очень похоже. Я пытался добавить строковый параметр в обязательном порядке, но при добавлении объекта С# начинается проблема.

Это мой основной С#:

[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. Я последовал другому примеру и создал как таблицу Person, так и PersonType, как показано ниже, в T-SQL:

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» не удалось, поскольку типы T-SQL и CLR для параметра «@personType» не совпадают».

Как мне заставить «PersonType» равняться «Person» класса С#, чтобы это работало правильно? Дайте мне знать, если я поступаю совершенно неправильно/если есть более простое решение. В идеале я буду передавать список с несколькими типами переменных внутри Person. Заранее спасибо.


person Wen    schedule 20.11.2018    source источник


Ответы (1)


Я думаю, вы неправильно поняли концепцию пользовательских типов. Это не то же самое, что пользовательские типы данных (сопоставление случайного имени с фактическим типом данных T-SQL) или пользовательские табличные типы (предопределенные схемы таблиц, используемые для создания табличных переменных, обычно используемые в качестве табличных параметров).

Попробуйте это для лучшего ознакомления: Определяемые пользователем типы CLR

Дайте мне знать, если я поступаю совершенно неправильно/если есть более простое решение. В идеале я буду передавать список с несколькими типами переменных внутри Person.

Если хранимая процедура должна была быть хранимой процедурой T-SQL, то лучшим способом сделать это было бы использование определяемого пользователем типа таблицы/TVP (т. е. CREATE TYPE PersonType AS TABLE...). Но поскольку SQLCLR не принимает TVP, вы можете сделать следующее:

  • составить список сложных «объектов» в виде XML-документа, который легко анализируется в .NET. Используйте SqlXml в качестве типа входного параметра .NET.
  • создайте локальную временную таблицу (т. е. начиная с одного #), заполните ее, а затем прочитайте из нее в хранимой процедуре SQLCLR, используя Context Connection = true в качестве строки подключения. Я не уверен, при каких условиях этот вариант будет лучше/проще, чем просто передача XML-документа, но это все же вариант.

Другие примечания:

  1. Вам не нужна часть param: атрибута SqlFacet.
  2. Используйте SqlString в качестве входящего типа данных вместо string. Получите строку .NET через свойство ParamName.Value. Проверьте, NULL ли через свойство ParamName.IsNull.
  3. Параметры не могут быть выражены как комбинации параметров. Это означает, что @person (@firstname nchar(300), @lastname nchar(300)) не является допустимым синтаксисом ни при каких условиях.

Дополнительные сведения о работе с SQLCLR в целом см. на странице Информация о SQLCLR.

person Solomon Rutzky    schedule 20.11.2018