NHibernate.Spatial 和 Sql 2008 地理类型 - 如何配置

Posted

技术标签:

【中文标题】NHibernate.Spatial 和 Sql 2008 地理类型 - 如何配置【英文标题】:NHibernate.Spatial and Sql 2008 Geography type - How to configure 【发布时间】:2010-12-02 11:36:10 【问题描述】:

我正在尝试将 Nhibernate 与 Sql 2008 Geography 类型一起使用,但遇到了困难。我正在使用 Fluent Nhibernate 来配置我比较陌生的配置,所以这也可能是问题所在。

首先,我试图坚持的类看起来像:

public class LocationLog : FluentNHibernate.Data.Entity

   public virtual new int Id get;set;
   public virtual DateTime TimeStamp get;set;
   public virtual GisSharpBlog.NetTopologySuite.Geometries.Point Location get;set;

映射类如下所示:

public class LocationLogMap : ClassMap<LocationLog>

   ImportType<GisSharpBlog.NetTopologySuite.Geometries.Point>();
   Id(x => x.Id);
   Map(x => x.TimeStamp).Generated.Insert();
   Map(x => x.Location);

为了在 Fluent Nhibernate 中使用 MsSql2008GeographyDialect,我创建了自己的配置类:

public class Sql2008Configuration
  : PersistenceConfiguration<Sql2008Configuration, MsSqlConnectionStringBuilder>

   public Sql2008Configuration()
   
      Driver<SqlClientDriver>();
   

   public static Sql2008Configuration MsSql2008
   
      get  return new Sql2008Configuration().Dialect<MsSql2008GeographyDialect>(); 
   

所以我有如下配置代码:

var configuration = Fluently.Configure()
  .Database(Sql2008Configuration.MsSql2008.ConnectionString(c => c.Is(connectionString)))
  .Mappings(m => m.FluentMappings
    .AddFromAssemblyOf<LocationLog>()
);

所有这些都是为了设置我在尝试将 LocationLog 类型持久保存到数据库时收到以下错误的事实:

在执行期间发生 .NET Framework 错误 执行用户定义的例程或 聚合“地理”: System.ArgumentException:24204: 空间参考标识符 (SRID) 是 无效。指定的 SRID 必须 匹配支持的 SRID 之一 显示在 sys.spatial_reference_systems 目录 看法。 System.ArgumentException:在 Microsoft.SqlServer.Types.SqlGeography.set_Srid(Int32 值)在 Microsoft.SqlServer.Types.SqlGeography.Read(BinaryReader 鼠 SqlGeography::.DeserializeValidate(IntPtr , Int32 , CClrLobContext* )

我已阅读以下有关如何配置和使用 Nhibernate Spatial 库的文章:

http://nhibernate.info/doc/spatial/configuration-and-mapping.html http://nhibernate.info/doc/spatial/sample-usage.html

但似乎都没有帮助。任何有配置 Nhibernate 以使用空间地理类型的经验并能提供任何见解的人都将不胜感激。

【问题讨论】:

【参考方案1】:

我在同一条船上,多亏了你的开始,我才开始工作(插入和读取空间数据)。对于其他感兴趣的人,首先 GisSharpBlog.NetTopologySuite.Geometries.Point 类位于 NetTopologySuite.dll 中,该类是 nHibernate.Spatial 下载的一部分。

其次,根据 James 的观点,确保将 SRID 设置为 4326。

最后,地图需要如下所示:

Map(a => a.Location).CustomType(typeof(NHibernate.Spatial.Type.GeometryType));

我正在使用 Geography,但我在某处读到使用 GeometryType 可能有效并且它对我有用(我插入了一些点并在数据库中验证了它)。我还读到最好为地理编写 SQL 查询,这样您就可以使用特殊的 SQL 2008 空间方法(而不是使用标准)。

【讨论】:

【参考方案2】:

Steve 是对的,您需要为您的几何类型显式设置 SRID。查看 NHibernate.Spatial 源代码(您可以使用 SVN 或其他方式签出),搜索 SRID 会发现代码中隐藏了这个作为注释提示:

<class name="MyGeoTableA">
    <property name="MyGeoColumn">
        <type name="NHibernate.Spatial.Type.GeometryType, NHibernate.Spatial">
            <param name="srid">1234</param>
        </type>
    </property>
</class>

看起来您需要将一个名为 SRID 的参数设置为您需要的任何数字(在 SRID 表中查找)。显然这是老式的 XML 配置,但 fluent 将在某处添加键/值字符串参数的方法。试试看吧。


编辑

经过更多研究,我发现尝试在列上设置 srid 属性失败了 NHibernate 的 XML 映射验证,它会抛出 XmlSchemaValidationException。相反,我发现 NetNopologySuite 中的几何类型在对象本身上有一个 SRID 属性,设置它可以使事情正常进行。例如

LocationLog log = new LocationLog  Location = new Point() ;
log.Location.SRID = 4326;
Session.Save(log);

虽然必须有更好的方法来做到这一点(配置它而不是一直设置它)但我还没有解决这个问题。如果您查看 MsSql2008GeometryType 类,它有一个名为 SetDefaultSRID(IGeometry) 的受保护方法 - 它一定是有原因的!

【讨论】:

【参考方案3】:

不是真正的答案,而是问题;-)

您是否在 GisSharpBlog.NetTopologySuite.Geometries.Point 对象上设置 SRID?

默认值(因为该点是几何图形)为 0,并且在尝试将 LocationLog.Location 属性作为地理信息持久保存时会给您一个 SQL 错误。 0 不是 sql 地理字段的有效 SRID。您需要从 sys.spatial_reference_systems 视图中指定一个。

您是否尝试过不使用 Fluent NHibernate?

从问题中消除尽可能多的组件。

【讨论】:

【参考方案4】:

您可以使用默认 SRID 创建自己的工厂。 例如,您可以为工厂创建一个外观,如下所示:

public static class Default

    private const int DefaultSrid = 4326;

    public static readonly IGeometryFactory Factory;

    static Default()
    
        Factory = new GeometryFactory(new PrecisionModel(), DefaultSrid);
    

并像这样使用它:

var point = Default.Factory.CreatePoint(new Coordinate(10, 10));

而不是使用“new”关键字。 您还可以在 IoC 框架中使用 Default.Factory 作为工厂方法来创建没有 Default 外观的新几何体。

【讨论】:

【参考方案5】:

我知道这几乎没有用,但无论如何。 在实施完所有 lain 所说的之后,请在您的 HQL 查询中使用 SetParameter 第三个 IType 参数。含义在

 Hero hero = openSession.Get<Hero>(3);    
openSession.CreateQuery(
              "from Hero h where NHSP.Distance(h.Location,:thislocation)<1000"
               ).SetParameter("thislocation", hero.Location, new CustomType(typeof(MsSql2008GeographyType), null) ).SetResultTransformer(new DistinctRootEntityResultTransformer())
               .List();

new CustomType(typeof(MsSql2008GeographyType), null) 必须通过,否则您将得到您非常熟悉的“System.ArgumentException: 24204”。

花了整整一夜才弄明白。

【讨论】:

以上是关于NHibernate.Spatial 和 Sql 2008 地理类型 - 如何配置的主要内容,如果未能解决你的问题,请参考以下文章

SQL的别名和SQL的执行顺序和SQL优化

SQL和T_SQL有啥区别

SQL和 FOXPRO有啥区别?

SQL 和 SQL*Plus 有啥区别? [关闭]

逻辑 SQL 和物理 SQL 有啥区别?

TSQL和SQL区别?