Следите за противоречивыми ссылками. Даже после чистых и перестроенных противоречивых ссылок все еще будет возникать проблема. Моя проблема заключалась между Афором и Согласием. Я удалил обе ссылки и повторно добавил ссылки, переучивая конкретную ссылку (в частности, мой случай, просто Accord).
Тип диска 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()
Вы должны использовать и проверить, имеют ли эта строка и столбец правильные значения, которые можно преобразовать в Int64 или нет. Попробуйте как это проверить Здесь .
Пожалуйста, сделайте следующее перед кастингом
bool success = Int64.TryParse(Convert.ToString(m["Capacity"]), out long number);
if (success)
{
Capacity = new SqlInt64((Int64)m["Capacity"]);
}
else
{
Capacity = 0;
}
Как вы узнали, ошибка связана с тем, что 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