在 .Net Core 的 ServiceStack.OrmLite 使用 SqlGeography
Use SqlGeography at ServiceStack.OrmLite in .Net Core
我尝试将 SqlGeography 添加到我的模型中,当我调用 create table 时出现奇怪的错误。
首先我添加这个包:Microsoft.SqlServer.Types
然后我创建我的模型,如下例所示:
public class Locations
{
public int Id { get; set; }
public string Name { get; set; }
public SqlGeography Location { get; set; }
}
然后调用CreateTableIfNotExists
创建table
private void CheckDB(IDbConnectionFactory dbConnectionFactory)
{
using (var db = dbConnectionFactory.Open())
{
db.CreateTableIfNotExists<Models.Entities.DbIpEntity>();
}
}
最后我得到了这个错误:
System.TypeLoadException HResult=0x80131522 Message=Could not load
type 'Microsoft.SqlServer.Server.IBinarySerialize' from assembly
'System.Data, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089'. Source=System.Private.CoreLib
StackTrace: at System.Signature.GetSignature(Void* pCorSig, Int32
cCorSig, RuntimeFieldHandleInternal fieldHandle, IRuntimeMethodInfo
methodHandle, RuntimeType declaringType) at
System.Reflection.RuntimeMethodInfo.FetchNonReturnParameters() at
System.Reflection.RuntimeMethodInfo.GetParametersNoCopy() at
System.Reflection.RuntimePropertyInfo.GetIndexParametersNoCopy() at
System.Reflection.RuntimePropertyInfo.GetIndexParameters() at
ServiceStack.OrmLite.OrmLiteConfigExtensions.GetModelDefinition(Type
modelType) at
ServiceStack.OrmLite.OrmLiteWriteCommandExtensions.CreateTable(IDbCommand
dbCmd, Boolean overwrite, Type modelType) at
ServiceStack.OrmLite.OrmLiteExecFilter.Exec[T](IDbConnection dbConn,
Func`2 filter) at
ServiceStack.OrmLite.OrmLiteSchemaApi.DropAndCreateTable[T](IDbConnection
dbConn) at GeoApi.AppHost.CheckDB(IDbConnectionFactory
dbConnectionFactory) in E:\Projects\Geo\AppHost.cs:line 48 at
GeoApi.AppHost.Configure(Container container) in
E:\Projects\Geo\AppHost.cs:line 40 at
ServiceStack.ServiceStackHost.Init() at
ServiceStack.NetCoreAppHostExtensions.UseServiceStack(IApplicationBuilder
app, AppHostBase appHost) at
GeoApi.Startup.Configure(IApplicationBuilder app, IHostingEnvironment
env) in E:\Projects\Geo\Startup.cs:line 49
在这个错误中,我意识到它正在寻找 .Net Framework 程序集(System.Data, Version=4.0.0.0
)而不是 .Net Core
定义 SqlGeography
的 ServiceStack.OrmLite.SqlServer.Converters and Microsoft.SqlServer.Types 仅分别适用于 .NET v4.5 和 .NET v4.0,因此至少需要 .NET v4.5 到 运行 并且不能在 .NET Core 中使用。
.net core 2.2 现在支持使用 GeoSpatial 数据 - https://docs.microsoft.com/en-us/ef/core/modeling/spatial
我能够根据 the SqlServerGeographyTypeConverter here.
拼凑出自己的 OrmLiteConverter
public class SqlServerIPointTypeConverter : OrmLiteConverter
{
public override string ColumnDefinition => "geography";
public override DbType DbType => DbType.Object;
public override string ToQuotedString(Type fieldType, object value)
{
if (fieldType != typeof(IPoint)) return base.ToQuotedString(fieldType, value);
string str = null;
if (value != null)
{
var geo = (IPoint) value;
str = geo.ToString();
}
str = (str == null) ? "null" : $"'{str}'";
return $"CAST({str} AS {ColumnDefinition})";
}
public override void InitDbParam(IDbDataParameter p, Type fieldType)
{
if (fieldType == typeof(IPoint))
{
var sqlParam = (SqlParameter)p;
sqlParam.IsNullable = fieldType.IsNullableType();
sqlParam.SqlDbType = SqlDbType.Udt;
sqlParam.UdtTypeName = ColumnDefinition;
}
base.InitDbParam(p, fieldType);
}
public override object FromDbValue(Type fieldType, object value)
{
switch (value)
{
case null:
case DBNull _:
return new Point(0, 0);
case IPoint point:
return point;
case string _:
return Parse(value.ToString());
default:
return base.FromDbValue(fieldType, value);
}
}
public override object ToDbValue(Type fieldType, object value)
{
switch (value)
{
case null:
case DBNull _:
return new Point(0, 0);
case IPoint _:
return value;
case string str:
return Parse(str);
default:
return base.ToDbValue(fieldType, value);
}
}
private static Point Parse(string rawPoint)
{
var split = rawPoint.Replace("POINT (", string.Empty)
.Replace(")", string.Empty)
.Trim()
.Split(new[] { " " }, StringSplitOptions.RemoveEmptyEntries);
var longitude = Convert.ToDouble(split[0]);
var latitude = Convert.ToDouble(split[1]);
return new Point(longitude, latitude);
}
}
然后在您的 AppHost 文件中:
SqlServerDialect.Provider.RegisterConverter<Point>(new SqlServerIPointTypeConverter());
只要您使用的是 dotnet core 2.2,并且引用了以下 Nuget 包,它就应该可以工作:
我尝试将 SqlGeography 添加到我的模型中,当我调用 create table 时出现奇怪的错误。
首先我添加这个包:Microsoft.SqlServer.Types
然后我创建我的模型,如下例所示:
public class Locations
{
public int Id { get; set; }
public string Name { get; set; }
public SqlGeography Location { get; set; }
}
然后调用CreateTableIfNotExists
创建table
private void CheckDB(IDbConnectionFactory dbConnectionFactory)
{
using (var db = dbConnectionFactory.Open())
{
db.CreateTableIfNotExists<Models.Entities.DbIpEntity>();
}
}
最后我得到了这个错误:
System.TypeLoadException HResult=0x80131522 Message=Could not load type 'Microsoft.SqlServer.Server.IBinarySerialize' from assembly 'System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'. Source=System.Private.CoreLib
StackTrace: at System.Signature.GetSignature(Void* pCorSig, Int32 cCorSig, RuntimeFieldHandleInternal fieldHandle, IRuntimeMethodInfo methodHandle, RuntimeType declaringType) at System.Reflection.RuntimeMethodInfo.FetchNonReturnParameters() at System.Reflection.RuntimeMethodInfo.GetParametersNoCopy() at System.Reflection.RuntimePropertyInfo.GetIndexParametersNoCopy() at System.Reflection.RuntimePropertyInfo.GetIndexParameters() at ServiceStack.OrmLite.OrmLiteConfigExtensions.GetModelDefinition(Type modelType) at ServiceStack.OrmLite.OrmLiteWriteCommandExtensions.CreateTable(IDbCommand dbCmd, Boolean overwrite, Type modelType) at ServiceStack.OrmLite.OrmLiteExecFilter.Exec[T](IDbConnection dbConn, Func`2 filter) at ServiceStack.OrmLite.OrmLiteSchemaApi.DropAndCreateTable[T](IDbConnection dbConn) at GeoApi.AppHost.CheckDB(IDbConnectionFactory dbConnectionFactory) in E:\Projects\Geo\AppHost.cs:line 48 at GeoApi.AppHost.Configure(Container container) in E:\Projects\Geo\AppHost.cs:line 40 at ServiceStack.ServiceStackHost.Init() at ServiceStack.NetCoreAppHostExtensions.UseServiceStack(IApplicationBuilder app, AppHostBase appHost) at GeoApi.Startup.Configure(IApplicationBuilder app, IHostingEnvironment env) in E:\Projects\Geo\Startup.cs:line 49
在这个错误中,我意识到它正在寻找 .Net Framework 程序集(System.Data, Version=4.0.0.0
)而不是 .Net Core
定义 SqlGeography
的 ServiceStack.OrmLite.SqlServer.Converters and Microsoft.SqlServer.Types 仅分别适用于 .NET v4.5 和 .NET v4.0,因此至少需要 .NET v4.5 到 运行 并且不能在 .NET Core 中使用。
.net core 2.2 现在支持使用 GeoSpatial 数据 - https://docs.microsoft.com/en-us/ef/core/modeling/spatial
我能够根据 the SqlServerGeographyTypeConverter here.
拼凑出自己的 OrmLiteConverterpublic class SqlServerIPointTypeConverter : OrmLiteConverter
{
public override string ColumnDefinition => "geography";
public override DbType DbType => DbType.Object;
public override string ToQuotedString(Type fieldType, object value)
{
if (fieldType != typeof(IPoint)) return base.ToQuotedString(fieldType, value);
string str = null;
if (value != null)
{
var geo = (IPoint) value;
str = geo.ToString();
}
str = (str == null) ? "null" : $"'{str}'";
return $"CAST({str} AS {ColumnDefinition})";
}
public override void InitDbParam(IDbDataParameter p, Type fieldType)
{
if (fieldType == typeof(IPoint))
{
var sqlParam = (SqlParameter)p;
sqlParam.IsNullable = fieldType.IsNullableType();
sqlParam.SqlDbType = SqlDbType.Udt;
sqlParam.UdtTypeName = ColumnDefinition;
}
base.InitDbParam(p, fieldType);
}
public override object FromDbValue(Type fieldType, object value)
{
switch (value)
{
case null:
case DBNull _:
return new Point(0, 0);
case IPoint point:
return point;
case string _:
return Parse(value.ToString());
default:
return base.FromDbValue(fieldType, value);
}
}
public override object ToDbValue(Type fieldType, object value)
{
switch (value)
{
case null:
case DBNull _:
return new Point(0, 0);
case IPoint _:
return value;
case string str:
return Parse(str);
default:
return base.ToDbValue(fieldType, value);
}
}
private static Point Parse(string rawPoint)
{
var split = rawPoint.Replace("POINT (", string.Empty)
.Replace(")", string.Empty)
.Trim()
.Split(new[] { " " }, StringSplitOptions.RemoveEmptyEntries);
var longitude = Convert.ToDouble(split[0]);
var latitude = Convert.ToDouble(split[1]);
return new Point(longitude, latitude);
}
}
然后在您的 AppHost 文件中:
SqlServerDialect.Provider.RegisterConverter<Point>(new SqlServerIPointTypeConverter());
只要您使用的是 dotnet core 2.2,并且引用了以下 Nuget 包,它就应该可以工作: