Получение ошибки для HierarchyId при извлечении данных с другого сервера и вставке их на мой сервер С#

Ошибка

Тип столбца «MemberHId» не поддерживается. Тип 'SqlHierarchyId'.

На обоих серверах тип данных один и тот же HierarchyId.

Я просто использую ADO.Net.

Сборка Microsoft.SqlServer.ManagedDTS версии 13.0.0.0 Мы используем Azure Sql.

Пробовал с разными версиями сборок sql

 DataTable dt = new DataTable();
 
 dt.Columns.Add("Code", typeof(string));
 dt.Columns.Add("Description", typeof(string));
 dt.Columns.Add("NodeId", typeof(int));
 dt.Columns.Add("MemberHId", typeof(SqlHierarchyId));
 dt.Columns.Add("Level", typeof(int));
                   
//Getting the data from serverAPI which is returning the data in the columns without null records.
 dt=apicall();

 SqlParameter returnParameter = cmd.Parameters.Add("RetVal", SqlDbType.Int);
 returnParameter.Direction = ParameterDirection.ReturnValue;
                
 cmd.CommandType = CommandType.StoredProcedure;
 cmd.CommandText = spName;
 cmd.Parameters.AddWithValue("@MemberH", dt);

 cmd.CommandTimeout = 0;
 cmd.Connection.Open();
 cmd.ExecuteNonQuery();// Its failing here

My Sp состоит из параметра табличного типа @MemberHType, и процедура возвращает строки со следующими столбцами:

    Name        | Type
    ------------+----------
    Code        | varchar
    Description | varchar
    NodeID      | smallint
    MemberHId   | hierarchyid
    Level       | smallint

Это процедура:

    alter PROCEDURE [dbo].[InsertHierarchyData]  
    (  
      @MemberHType MemberH READONLY  
    )  
    AS  
    
    truncate table test
    BEGIN TRY   
     
       insert into test values ('start select')
      
     --create table test (errormessage varchar(1000))
    
     IF EXISTS (SELECT TOP 1 1 FROM @MemberHType)  
     BEGIN  
    
     insert into test values ('Inside first Insert start')
      INSERT INTO HierarchyStaging  
      (  
       Code  
       ,[Description]  
       ,NodeID  
       ,MemberhHId  
       ,[Level]  
      )  
      SELECT    
        Code  
        ,[Description]  
        ,NodeId  
        ,MemberhHId  
        ,[Level]  
      FROM @MemberHType  
      insert into test values ('Inside first Insert end')
     END  
     END TRY    
    BEGIN CATCH    
     SELECT   @comment = ERROR_MESSAGE()    
       ,@Status = 'Error'    
     SET   @comment = CONVERT(NVARCHAR(3000),@Comment) + ' Error Severity: ' + CAST(ERROR_SEVERITY() AS varchar(25)) + ' Error state: 30'    
     GOTO ErrorHandler    
    END CATCH    
    The Column in c# is SqlHierarchyId.

Трассировки стека:

at System.Data.SqlClient.TdsParser.TdsExecuteRPC(SqlCommand cmd, _SqlRPC[] rpcArray, Int32 timeout, Boolean inSchema, SqlNotificationRequest notificationRequest, TdsParserStateObject stateObj, Boolean isCommandProc, Boolean sync, TaskCompletionSource`1 completion, Int32 startRpc, Int32 startParam)
   at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, Boolean inRetry, SqlDataReader ds, Boolean describeParameterEncryptionRequest)
   at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry)
   at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion, String methodName, Boolean sendToPipe, Int32 timeout, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry)
   at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()

person Rajiv Bansal    schedule 04.09.2019    source источник
comment
Вы можете добавить свой sproc?   -  person Ed Bangga    schedule 04.09.2019
comment
Azure SQL поддерживает идентификатор иерархии: docs.microsoft.com/en-us/sql/t-sql/data-types/ — действительно ли вы используете хранилище данных SQL Azure?   -  person Caius Jard    schedule 04.09.2019
comment
Также я понимаю необходимость скрывать конфиденциальную информацию при публикации в Интернете, но, пожалуйста, не скрывайте свои данные до такой степени, что вы заменяете весь список/массив/таблицу сложных типов простой строкой данных в @table вашего sproc. параметр. Показать реальный пример объекта с фиктивными данными   -  person Caius Jard    schedule 04.09.2019
comment
На этот вопрос нельзя ответить, основываясь только на содержащейся в нем информации. Пожалуйста, постарайтесь помнить, что никто из нас не может читать ваши мысли. Создайте правильный минимально воспроизводимый пример, если вы хотите, чтобы на ваш вопрос был дан ответ.   -  person Zohar Peled    schedule 04.09.2019
comment
Хорошо, отредактирую   -  person Rajiv Bansal    schedule 04.09.2019
comment
Пожалуйста, дайте мне знать, если вам нужна дополнительная информация, так как я борюсь с этой проблемой с 3 дней, перепробовал все возможные вещи.   -  person Rajiv Bansal    schedule 04.09.2019
comment
@ Caius Jard, @Zohar- дайте мне знать, если вам нужны подробности, которыми я тоже могу поделиться.   -  person Rajiv Bansal    schedule 04.09.2019


Ответы (1)


Если я правильно понимаю документацию, вы не можете использовать SqlHierarchyId в качестве типа данных столбца DataColumn.

Он не отображается в системе . .Data.SqlTypes Namespace, а также отсутствует в Сопоставления типов данных SQL Server, что означает отсутствие задокументированного встроенного преобразования между HierarchyId SQL Server и встроенным типом в .Net framework. (Конечно, известно, что в SQL Server существуют недокументированные функции, но я бы не рекомендовал полагаться на это).

Однако вы можете преобразовать HierarchyId в nvarchar с помощью простого cast в T-SQL, когда вы читаете его в своем приложении C# (которое внутри вызывает ToString()):

CAST(MemberhHId  AS nvarchar(4000)) as MemberHId

и преобразуйте его обратно, используя cast, когда вы вставляете данные (которые внутри вызывают Parse()):

CAST(MemberHId AS hierarchyid) 
person Zohar Peled    schedule 04.09.2019
comment
Привет, Зоар, SqlHierarchyId присутствует в Microsoft.SqlServer.Types.dll, и возникает ошибка при назначении sp, т.е. при передаче параметра из C# в sp. - person Rajiv Bansal; 04.09.2019
comment
Да, потому что это тип CLR в SQL Server. это не означает, что его можно использовать как тип при вставке параметра с табличным значением с помощью ADO.Net. - person Zohar Peled; 04.09.2019
comment
Если я также удалю, автоматически сгенерированный тип DataColumn будет SqlHierarchyId, и ошибка будет такой же. - person Rajiv Bansal; 04.09.2019
comment
А также, когда я использую тип столбца в качестве строки, он работает, почему так? и данные, которые есть, не будут повреждены. - person Rajiv Bansal; 04.09.2019
comment
Я не уверен, что понимаю ваш последний комментарий. Вы говорите, что ADO.Net автоматически преобразует HierarchyId SQL Server в строку и обратно для вас? Если это так, то все еще проще, чем я думал... - person Zohar Peled; 04.09.2019
comment
Да, он делает это (ADO.Net автоматически преобразует HierarchyId SQL Server в строку).... и как мне остановить это, как я уже сказал, если я возьму тип столбца как String, поток данных будет работать без проблем. - person Rajiv Bansal; 04.09.2019
comment
Почему вы хотите остановить это? кажется, что вы получаете то, что хотите, не так ли? - person Zohar Peled; 04.09.2019
comment
Да, но это то же самое исключение, о котором я упоминал. - person Rajiv Bansal; 04.09.2019
comment
Я запутался. Когда тип данных столбца в таблице данных С# равен string, вы говорите, что ADO.Net автоматически преобразует heirarchyId для вас, но вы все еще получаете сообщение об ошибке? - person Zohar Peled; 04.09.2019
comment
Нет, вы меня неправильно понимаете..... поэтому, когда я не указываю типы столбцов, С# преобразует тип столбца в SqlHierarchyId. И когда я специально использую тип столбца как строку, он работает без проблем - person Rajiv Bansal; 04.09.2019
comment
По общему признанию, английский не является моим родным языком, но, насколько мне известно, бесперебойная работа означает, что все работает так, как должно, поэтому, если вы устанавливаете тип данных столбца в строку, вы говорите, что данные передаются правильно из одной базы данных в другую. Это правильно? - person Zohar Peled; 04.09.2019
comment
Да, это правильно после того, как я установил его в строку, но здесь меня беспокоит только потеря данных, если я преобразую его в строку. - person Rajiv Bansal; 04.09.2019
comment
Что ж, это довольно легко проверить... Просто создайте демонстрационное приложение, которое берет информацию из одной таблицы и вставляет ее в другую таблицу той же базы данных. Сравните содержимое обеих таблиц после завершения, и тогда вы узнаете, потеряли ли вы данные или нет. Лично, если это то, что ADO.Net делает для вас, я бы не стал слишком беспокоиться, но никто не мешает вам тестировать.... - person Zohar Peled; 04.09.2019