如何从 T-SQL、SQL Server 调用 C# 代码

发布于 2025-01-11 14:02:34 字数 3489 浏览 0 评论 0原文

一点上下文,我需要一种方法来无损插入/选择/比较单精度和双精度浮点到 SQL Server 数据库中,而不使用参数,我想我会很聪明,并将 DLL 作为超快速函数调用。

我编写并测试了这个 C# 类(我已经对其进行了充分测试):

using System;
using System.Linq;
using System.Reflection;

namespace SqlServerCast
{
    public class SqlServerCast
    {
        static public char ByteOrder;

        public enum ByteOrderEnum {
            BigEndian = 1,     /*  The most significant byte (highest address) is stored first. */
            LittleEndian = 0   /*  The least significant byte (lowest address) is stored first. */}

        public static void Main()
        {
            Assembly assem = typeof(SqlServerCast).Assembly;
            Object o = assem.CreateInstance("SqlServerCast", false,
                BindingFlags.ExactBinding,
                null, new Object[] { 2 }, null, null); 
        }

        public SqlServerCast(char val)    //  constructor
        {
            if (val != 0) ByteOrder = (char) ByteOrderEnum.BigEndian;
            else ByteOrder = (char) ByteOrderEnum.LittleEndian;
        }

        public static double CastToDBL(string str) {return BitConverter.ToDouble(StringToByteArray(str), 0);}

        public static float CastToSGL(string str)  {return BitConverter.ToSingle(StringToByteArray(str), 0);}

        private static string Dash = "-", NullStr = null;
        public static string CastFromDBL(double dbl) {
            switch (ByteOrder)
            {
                case (char)ByteOrderEnum.BigEndian:   //  actually, network byte order, big endian
                    byte[] bytes = BitConverter.GetBytes(dbl);
                    return BitConverter.ToString(bytes.Reverse().ToArray()).Replace(Dash, NullStr);
                case (char)ByteOrderEnum.LittleEndian:
                    return BitConverter.ToString(BitConverter.GetBytes(dbl)).Replace(Dash, NullStr);
                default:
                    return null;
            }
         }

        public static string CastFromSGL(float sgl)
        {
            switch (ByteOrder)
            {
                case (char)ByteOrderEnum.BigEndian:   //  actually, network byte order, big endian
                    byte[] bytes = BitConverter.GetBytes(sgl);
                    return BitConverter.ToString(bytes.Reverse().ToArray()).Replace(Dash, NullStr);
                case (char)ByteOrderEnum.LittleEndian:
                    return BitConverter.ToString(BitConverter.GetBytes(sgl)).Replace(Dash, NullStr);
                default:
                    return null;
            }
        }

        private static byte[] StringToByteArray(String hex)
        {
            int NumberChars = hex.Length;
            byte[] bytes = new byte[NumberChars / 2];
            for (int i = 0; i < NumberChars; i += 2)
                bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
            switch (ByteOrder) {
                case (char) ByteOrderEnum.BigEndian:   //  actually, network byte order, big endian
                    return bytes.Reverse().ToArray();
                case (char) ByteOrderEnum.LittleEndian:
                    return bytes;
                default:
                    return null;
            }
        }
    }
}

...尝试遵循 SO 和 MSDN 上关于 T-SQL 可调用 DLL 的规定,到目前为止我收到此错误:

消息 6544,级别 16,状态 1,第 1 行
为程序集“SqlServerCast”创建程序集失败,因为程序集“SqlServerCast”格式错误或不是纯 .NET 程序集。
无法验证的 PE 标头/本机存根。

有人可以在这里给我一步一步的成功之路吗?我被困住了......

顺便说一句:我知道创建哈希值,我认为这还不是问题。

A little context, I need a means to losslessly insert/select/compare single and double precision floating point into a SQL Server database without using parameters, thought I'd be clever and call a DLL as a super-fast function.

I wrote and tested this C# class (which I've well-tested):

using System;
using System.Linq;
using System.Reflection;

namespace SqlServerCast
{
    public class SqlServerCast
    {
        static public char ByteOrder;

        public enum ByteOrderEnum {
            BigEndian = 1,     /*  The most significant byte (highest address) is stored first. */
            LittleEndian = 0   /*  The least significant byte (lowest address) is stored first. */}

        public static void Main()
        {
            Assembly assem = typeof(SqlServerCast).Assembly;
            Object o = assem.CreateInstance("SqlServerCast", false,
                BindingFlags.ExactBinding,
                null, new Object[] { 2 }, null, null); 
        }

        public SqlServerCast(char val)    //  constructor
        {
            if (val != 0) ByteOrder = (char) ByteOrderEnum.BigEndian;
            else ByteOrder = (char) ByteOrderEnum.LittleEndian;
        }

        public static double CastToDBL(string str) {return BitConverter.ToDouble(StringToByteArray(str), 0);}

        public static float CastToSGL(string str)  {return BitConverter.ToSingle(StringToByteArray(str), 0);}

        private static string Dash = "-", NullStr = null;
        public static string CastFromDBL(double dbl) {
            switch (ByteOrder)
            {
                case (char)ByteOrderEnum.BigEndian:   //  actually, network byte order, big endian
                    byte[] bytes = BitConverter.GetBytes(dbl);
                    return BitConverter.ToString(bytes.Reverse().ToArray()).Replace(Dash, NullStr);
                case (char)ByteOrderEnum.LittleEndian:
                    return BitConverter.ToString(BitConverter.GetBytes(dbl)).Replace(Dash, NullStr);
                default:
                    return null;
            }
         }

        public static string CastFromSGL(float sgl)
        {
            switch (ByteOrder)
            {
                case (char)ByteOrderEnum.BigEndian:   //  actually, network byte order, big endian
                    byte[] bytes = BitConverter.GetBytes(sgl);
                    return BitConverter.ToString(bytes.Reverse().ToArray()).Replace(Dash, NullStr);
                case (char)ByteOrderEnum.LittleEndian:
                    return BitConverter.ToString(BitConverter.GetBytes(sgl)).Replace(Dash, NullStr);
                default:
                    return null;
            }
        }

        private static byte[] StringToByteArray(String hex)
        {
            int NumberChars = hex.Length;
            byte[] bytes = new byte[NumberChars / 2];
            for (int i = 0; i < NumberChars; i += 2)
                bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
            switch (ByteOrder) {
                case (char) ByteOrderEnum.BigEndian:   //  actually, network byte order, big endian
                    return bytes.Reverse().ToArray();
                case (char) ByteOrderEnum.LittleEndian:
                    return bytes;
                default:
                    return null;
            }
        }
    }
}

...trying to follow the prescriptions on SO and MSDN for T-SQL -callable DLLs and so far I get this error:

Msg 6544, Level 16, State 1, Line 1
CREATE ASSEMBLY for assembly 'SqlServerCast' failed because assembly 'SqlServerCast' is malformed or not a pure .NET assembly.
Unverifiable PE Header/native stub.

Can someone give me a step-by-step path to success here? I'm stuck...

BTW: I know about creating the hashes, I don't think that's the issue yet.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

初与友歌 2025-01-18 14:02:34

这些说明适用于 Microsoft SQL Server Management Studio 2014。

导入程序集

首先,您需要通过导航到“新建程序集”对话框窗口将该程序集导入到 SQL Server Management Studio 内的数据库中

DatabaseName -> Programmability -> Assemblies -> (Right Click) 'New Assembly...'

:在“新建程序集”对话框窗口中,选择“程序集路径”字段下的“浏览”,然后选择要导入的程序集。调整权限并单击确定。

在 SQL 函数中包装汇编方法

接下来,您需要创建 sql 函数来包装您的汇编方法,如下所示:

CREATE FUNCTION [dbo].[fn_funcName](@str [varchar](max))
RETURNS 
   varchar(max) 
WITH EXECUTE AS CALLER
AS 
EXTERNAL NAME [YourSqlAssemblyName].[YourAssemblyName.Class1].[GetName]

如果您想从函数返回表,请阅读 .NET 中的 SqlFunctionAttribute。

These instructions are for Microsoft SQL Server Management Studio 2014.

Import the Assembly

First of all you need to import that assembly into your database inside SQL Server Management Studio by navigating to the New Assembly dialog window:

DatabaseName -> Programmability -> Assemblies -> (Right Click) 'New Assembly...'

Inside the 'New Assembly' dialog window, chose Browse under the Path to assembly field and select the assembly you want to import. Adjust Permissions and click ok.

Wrap Assembly Methods in a SQL Function

Next you need to create sql function to wrap your assembly method like this:

CREATE FUNCTION [dbo].[fn_funcName](@str [varchar](max))
RETURNS 
   varchar(max) 
WITH EXECUTE AS CALLER
AS 
EXTERNAL NAME [YourSqlAssemblyName].[YourAssemblyName.Class1].[GetName]

If you want to return table from your function read about SqlFunctionAttribute in .NET.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文