简体   繁体   English

在.Net Core中的ServiceStack.OrmLite上使用SqlGeography

[英]Use SqlGeography at ServiceStack.OrmLite in .Net Core

I try to add SqlGeography to my model and when I call create table I got weird error. 我尝试将SqlGeography添加到我的模型中,当我调用create table时出现奇怪的错误。

First I add this package: Microsoft.SqlServer.Types 首先,我添加以下程序包: Microsoft.SqlServer.Types

Then I create my model like example at below: 然后在下面创建我的模型,例如下面的示例:

public class Locations 
{
   public int Id { get; set; }
   public string Name { get; set; }
   public SqlGeography Location { get; set; }
}

Then call CreateTableIfNotExists to create table 然后调用CreateTableIfNotExists创建表

private void CheckDB(IDbConnectionFactory dbConnectionFactory)
{
    using (var db = dbConnectionFactory.Open())
    {
        db.CreateTableIfNotExists<Models.Entities.DbIpEntity>();
    }
}

And at end I got this error: 最后我得到了这个错误:

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'. System.TypeLoadException HResult = 0x80131522消息=无法从程序集“ System.Data,版本= 4.0.0.0,区域性=中性,PublicKeyToken = b77a5c561934e089”中加载类型“ Microsoft.SqlServer.Server.IBinarySerialize”。 Source=System.Private.CoreLib 来源= 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 a StackTrace:在System.Reflection.RuntimeMethodInfo.GetParameters。在ServiceStack.OrmLite.OrmLite.OrmLite.OrmLiteWriteCommandExtensions.CreateTable(IDbCommand dbCmd,在布尔值覆盖。在类型为TypeType的ServiceType。 E:\\ Projects \\ Geo \\ AppHost中的GeoApi.AppHost.CheckDB(IDbConnectionFactory dbConnectionFactory)中的ServiceStack.OrmLite.OrmLiteSchemaApi.DropAndCreateTable [T](IDbConnection dbConn)中的OrmLiteExecFilter.Exec [T](IDbConnection dbConn,Func`2筛选器)。在E:\\ Projects \\ Geo \\ AppHost.cs:line 40 a中的GeoApi.AppHost.Configure(容器容器)处的cs:line 48 t 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 t E:\\ Projects \\ Geo \\ Startup.cs:line 49中ServiceStack.NetCoreAppHostExtensions.UseServiceStack(IApplicationBuilder app,AppHostBase appHost)的ServiceStack.ServiceStackHost.Init()在GeoApi.Startup.Configure(IApplicationBuilder app,IHostingEnvironment env)

In this error I realized it's looking for .Net Framework assembly ( System.Data, Version=4.0.0.0 ) not .Net Core 在此错误中,我意识到它正在寻找.Net Framework程序集( System.Data, Version=4.0.0.0 ),而不是.Net Core

定义SqlGeographyServiceStack.OrmLite.SqlServer.ConvertersMicrosoft.SqlServer.Types分别仅适用于.NET v4.5和.NET v4.0,因此它至少需要运行.NET v4.5才能运行。不能在.NET Core中使用。

.net core 2.2 now supports working with GeoSpatial data - https://docs.microsoft.com/en-us/ef/core/modeling/spatial .NET 2.2的核心现在支持地理空间数据的工作- https://docs.microsoft.com/en-us/ef/core/modeling/spatial

I was able to knock together my own OrmLiteConverter based around the SqlServerGeographyTypeConverter here. 我可以根据SqlServerGeographyTypeConverter将自己的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);
    }
}

Then in your AppHost file: 然后在您的AppHost文件中:

SqlServerDialect.Provider.RegisterConverter<Point>(new SqlServerIPointTypeConverter());

As long as you are on dotnet core 2.2, and have the following Nuget packages referenced, it should work: 只要您使用的是dotnet core 2.2,并引用了以下Nuget程序包,它就可以工作:

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM