SQL Server CLR Int64 to SQLInt64 Указанное приведение недопустимо

Следите за противоречивыми ссылками. Даже после чистых и перестроенных противоречивых ссылок все еще будет возникать проблема. Моя проблема заключалась между Афором и Согласием. Я удалил обе ссылки и повторно добавил ссылки, переучивая конкретную ссылку (в частности, мой случай, просто Accord).

4
задан Niklas 18 January 2019 в 11:06
поделиться

3 ответа

Тип диска m ["Емкость"] - UInt64. Я использовал эту функцию, чтобы узнать, какой тип данных использовался.

m["Capacity"].GetType().ToString();

Я изменил CLR для вывода только типа данных для этой цели.

Зная тип, я провел некоторое исследование, как конвертировать UInt64 в Int64, и, наконец, нашел подход:

Int64 int64cap;
Int64.TryParse(m["Capacity"].ToString(), out int64cap);

Я не знаю, правильное ли это решение, но оно работает для меня.

Вот полный код

public class WMIQuery
{
    [SqlFunction(FillRowMethodName = "FillRow")]
    public static IEnumerable InitMethod()
    {


        ManagementScope scope = new ManagementScope();

        scope = new ManagementScope(@"\\localhost\root\CIMV2");
        scope.Connect();

        SelectQuery query = new SelectQuery("SELECT Name, Capacity, Freespace FROM Win32_Volume WHERE DriveType=3");
        ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query);


        ManagementObjectCollection retObjectCollection = searcher.Get ( );

        return retObjectCollection;
    }

    public static void FillRow(Object obj, out SqlString Name, out SqlDecimal Capacity, out SqlDecimal Freespace)
    {
        ManagementObject m = (ManagementObject)obj;

        Name = new SqlString((string)m["name"]);


        Int64 int64cap;
        Int64.TryParse(m["Capacity"].ToString(), out int64cap);
        decimal decCap;
        decCap = int64cap / 1073741824; // to GB
        decCap = Math.Round(decCap, 2);
        Capacity = new SqlDecimal(decCap);

        Int64 int64Free;
        Int64.TryParse(m["Freespace"].ToString(), out int64Free);
        decimal decFree;
        decFree = int64Free / 1073741824; // to GB
        decFree = Math.Round(decFree, 2);
        Freespace = new SqlDecimal(decFree);




    }


}

SQL для запуска этого материала:

CREATE ASSEMBLY [MyFirstAssembly]
FROM 'C:\MyFirstAssembly.dll'
WITH PERMISSION_SET = UNSAFE
GO

CREATE FUNCTION [dbo].[WMIQuery]()
RETURNS  TABLE (
    [Name] [nvarchar](4000) NULL,
    [Capacity] decimal(18,2) NULL,
    [Freespace] decimal(18,2) NULL
) WITH EXECUTE AS CALLER
AS 
EXTERNAL NAME [MyFirstAssembly].[WMIQuery].[InitMethod]
GO

select * from WMIQuery()
0
ответ дан Niklas 18 January 2019 в 11:06
поделиться

Вы должны использовать и проверить, имеют ли эта строка и столбец правильные значения, которые можно преобразовать в Int64 или нет. Попробуйте как это проверить Здесь .

Пожалуйста, сделайте следующее перед кастингом

bool success = Int64.TryParse(Convert.ToString(m["Capacity"]), out long number);
if (success)
{
   Capacity = new SqlInt64((Int64)m["Capacity"]);
}
else
{
   Capacity = 0;
}
0
ответ дан Suraj Kumar 18 January 2019 в 11:06
поделиться

Как вы узнали, ошибка связана с тем, что m["Capacity"] является неподписанным, не подписанным, Int64. Чтобы исправить, просто используйте класс Convert следующим образом:

        Capacity = new SqlInt64(Convert.ToInt64(m["Capacity"]));
        Freespace = new SqlInt64(Convert.ToInt64(m["Freespace"]));

Я проверил это с вашим кодом, получил ту же ошибку, прежде чем вносить какие-либо изменения, а затем внес изменения, рекомендованные выше, и теперь я получаю правильный вывод.

Хотя это и не является частью проблемы, но в целом (изначально был входной параметр String Querytext): для входных параметров / возвращаемых типов, пожалуйста, используйте типы Sql* вместо собственных типов для большинства типов данных (object для SQL_VARIANT и DateTime для DATETIME2 являются заметными исключениями). Итак, используйте SqlString вместо String для параметра Querytext (или просто удалите входной параметр, поскольку он не используется). Вы можете получить нативный .NET string из параметра, используя свойство Value (например, Querytext.Value), которое есть во всех типах Sql* (которое возвращает ожидаемый нативный тип в каждом случае).

Для получения дополнительной информации об использовании SQLCLR, пожалуйста, посетите: SQLCLR Info

HOWEVER, и, возможно, что еще более важно: посмотреть, что именно вы запрашиваете через WMI, похоже, вы получаете информацию, для которой уже есть DMV, sys.dm_os_volume_stats. Вы можете получить точно такую ​​же информацию для всех дисков / томов, на которых у вас уже есть файлы, с помощью следующего запроса:

SELECT DISTINCT vol.[volume_mount_point], vol.[volume_id], vol.[logical_volume_name],
                vol.[file_system_type], vol.[total_bytes], vol.[available_bytes],
                (vol.[total_bytes] - vol.[available_bytes]) AS [used_bytes]
FROM sys.master_files files
CROSS APPLY sys.dm_os_volume_stats(files.[database_id], files.[file_id]) vol
0
ответ дан Solomon Rutzky 18 January 2019 в 11:06
поделиться
Другие вопросы по тегам:

Похожие вопросы: