NHibernate.Spatial和Sql 2008 Geography类型 - 如何进行配置

22
我正在尝试使用Nhibernate和Sql 2008的地理类型并遇到了困难。我正在使用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类型持久化到数据库时遇到以下错误而设置的:

执行用户定义的例程或聚合“geography”时发生.NET Framework错误:System.ArgumentException:24204:空间参考标识符(SRID)无效。指定的SRID必须与在sys.spatial_reference_systems目录视图中显示的受支持的SRID之一匹配。System.ArgumentException:在Microsoft.SqlServer.Types.SqlGeography.set_Srid(Int32 value)处 在Microsoft.SqlServer.Types.SqlGeography.Read(BinaryReader r) 在SqlGeography :: .DeserializeValidate(IntPtr,Int32,CClrLobContext *)

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

但是两篇文章都没有帮助。如果有任何有经验的人可以提供有关配置Nhibernate以使用空间地理类型的任何见解,那将不胜感激。

5个回答

10
我和你的情况类似,感谢你的启动,我已经使它工作(插入和读取空间数据)。对于任何其他感兴趣的人,首先需要注意的是,GisSharpBlog.NetTopologySuite.Geometries.Point类在NetTopologySuite.dll中,后者是nHibernate.Spatial下载的一部分。
其次,按照James的建议,请确保将SRID设置为4326。
最后,地图应该看起来像这样:
Map(a => a.Location).CustomType(typeof(NHibernate.Spatial.Type.GeometryType));

我正在使用Geography,但我在某个地方读到使用GeometryType可能会起作用,对我来说确实如此(我插入了一些点并在数据库中进行了验证)。 我还读到最好为Geography编写SQL查询,这样您就可以使用特殊的SQL 2008空间方法(而不是使用Criteria)。


2
史蒂夫是对的,你需要为你的几何类型显式设置一个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)——一定是有原因的!”

1

我知道这几乎没有用,但无论如何。 在实现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” 这个非常熟悉的错误。

我花了整夜才弄清楚这个问题。


1

您可以使用默认的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));

可以使用 Default.Factory 作为工厂方法在您的 IoC 框架中创建新的几何体,而不是使用 "new" 关键字。


1

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

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

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

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

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接