C# 执行CLR SQL函数时出现问题
我创建了一个简单的1方法DLL,使用内部web服务将字符串地址转换为Lat/Lon字符串。代码就是这样的:C# 执行CLR SQL函数时出现问题,c#,sql-server,sqlclr,C#,Sql Server,Sqlclr,我创建了一个简单的1方法DLL,使用内部web服务将字符串地址转换为Lat/Lon字符串。代码就是这样的: public class GeoCodeLib { [SqlFunction(IsDeterministic=false)] public SqlString GetLatLon(SqlString addr) { Geo.GeoCode gc = new Geo.GeoCode(); Geo.Location loc = gc.Ge
public class GeoCodeLib
{
[SqlFunction(IsDeterministic=false)]
public SqlString GetLatLon(SqlString addr)
{
Geo.GeoCode gc = new Geo.GeoCode();
Geo.Location loc = gc.GetLocation(addr.Value);
return new SqlString(string.Format("{0:N6}, {1:N6}", loc.LatLon.Latitude, loc.LatLon.Longitude));
}
}
我的目标是.NETFramework2.0。我们正在使用SQL Server 2008 R2。该程序集已添加到数据库(该程序集称为GeoCodeSqlLib.dll)。我们没有对它设置权限
我似乎不能称之为。我试过:
select GeoCodeSqlLib.GeoCodeLib.GetLatLon('12143 Thompson Dr. Fayetteville, AR 72704')
CREATE FUNCTION GetLatLon(@amount varchar(max)) RETURNS varchar(max)
AS EXTERNAL NAME GeoCodeSqlLib.GeoCodeLib.GetLatLon
这给了我一个信息,找不到列“GeoCodeSqlLib”或用户定义函数或聚合“GeoCodeSqlLib.GeoCodeLib.GetLatLon”,或者名称不明确。
我试过:
select GeoCodeSqlLib.GeoCodeLib.GetLatLon('12143 Thompson Dr. Fayetteville, AR 72704')
CREATE FUNCTION GetLatLon(@amount varchar(max)) RETURNS varchar(max)
AS EXTERNAL NAME GeoCodeSqlLib.GeoCodeLib.GetLatLon
这给了我一条消息,在程序集“GeoCodeSqlLib”中找不到类型“GeoCodeLib”。
我显然错过了什么。文档的示例都是非常基本的,无论我缺少什么步骤,我都无法在文档中找到它
更新
谢谢你的帮助。所以有几件事:
- 我需要使其成为外部访问,以便能够进行web服务调用。。我没有意识到我需要创建一个SQL Server项目。我只是在做一个普通的C#class库李>
- 因此,我创建了SQL Server项目。SQL Server项目不支持web服务引用。我尝试添加对原始DLL的引用,因此新的SQL Server项目DLL充当原始DLL的代理(原始问题中的代码)李>
- 然而,这给了我:
但我无法将其添加到目录中,因为它需要 外部访问,我不能从非SQL Server项目(即 据我所知)程序集“geocodesqllib,version…”在 SQL目录。
<applicationSettings>
<GeoCodeSqlLib.Properties.Settings>
<setting name="GeoCodeSqlLib_ourserver_GeoCode" serializeAs="String">
<value>http://ourserver/GeoCode.svc</value>
</setting>
</GeoCodeSqlLib.Properties.Settings>
</applicationSettings>
有几件事:
static
CREATE FUNCTION
语句中,需要使用NVARCHAR
而不是VARCHAR
。SQLCLR不支持VARCHAR
CREATE FUNCTION
语句中,输入参数和返回类型不需要使用MAX
。纬度和经度的组合总是少于4000个字符,我很确定地址也会少于4000个字符。签名中甚至只有一个MAX
数据类型,这无疑会对性能造成影响。你最好让这两个都成为NVARCHAR(4000)
外部名称
语法为:
EXTERNAL NAME AssemblyName.[NamespaceName.ClassName].MethodName;
因此,最终的结果应该是:
CREATE FUNCTION dbo.GetLatLon(@Address NVARCHAR(4000))
RETURNS NVARCHAR(4000)
AS EXTERNAL NAME GeoCodeSqlLib.[{namespace_name}.GeoCodeLib].GetLatLon;
根据问题中的更新部分: 不,您不需要将VisualStudio项目设置为“数据库项目”,但它确实使发布变得更容易 为了将
GeoCodeSqlLib
库设置为EXTERNAL\u ACCESS
,您可以通过Visual Studio中数据库项目的项目属性来执行此操作。您还可以将WITH PERMISSION\u SET=EXTERNAL\u ACCESS
添加到CREATE ASSEMBLY
语句中,这是Visual Studio发布过程(由SSDT处理)正在执行的所有操作
现在,为了能够将任何程序集设置为外部访问
(甚至设置为不安全
),您需要执行以下操作:
master
数据库中,从该DLL创建一个非对称密钥master
中,使用该非对称密钥创建登录名外部访问程序集
权限\u SET=EXTERNAL\u ACCESS
(在CREATE ASSEMBLY
或ALTER ASSEMBLY
语句中,为使用该特定键签名的任何程序集执行)而不会出现错误
这可能有助于更清楚地了解如何首先使用SQLCLR。请参阅我在SQL Server Central上就此主题撰写的系列文章(阅读该网站上的内容需要免费注册):
该系列文章中的第7级甚至描述了一种使用VisualStudio/SSDT管理上述步骤的方法,以使其以自动化的方式工作,因为VS/SSDT不处理这方面的安全性(这很可悲,因为它鼓励人们在上轻松地将数据库设置为可信,这是一个安全漏洞)。我的下一篇文章将介绍在Visual Studio中使用T-4模板的一种更简单的方法
有关更新2的部分和关于此答案的其他评论: