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

时间:2009-09-29 21:56:46

标签: c# nhibernate sql-server-2008 fluent-nhibernate geography

我正在尝试将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);
}

为了将MsSql2008GeographyDialect与Fluent Nhibernate一起使用,我创建了自己的配置类:

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:The   空间参考标识符(SRID)是   无效。指定的SRID必须   匹配其中一个受支持的SRID   显示在   sys.spatial_reference_systems目录   视图。 System.ArgumentException:at   Microsoft.SqlServer.Types.SqlGeography.set_Srid(的Int32   价值)   Microsoft.SqlServer.Types.SqlGeography.Read(BinaryReader在   r)at   SqlGeography ::。DeserializeValidate(IntPtr的   ,Int32,CClrLobContext *)

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

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

5 个答案:

答案 0 :(得分:10)

我在同一条船上,并且由于你的开始,我得到了它(插入和读取空间数据)。对于其他感兴趣的人,首先是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 Spatial方法(而不是使用Criteria)。

答案 1 :(得分: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配置,但是流畅的将有一个方法来添加键/值字符串参数。试一试。


修改

经过一番研究后,我发现尝试在列上设置srid属性失败了NHibernate的XML映射验证,它抛出了一个XmlSchemaValidationException。相反,我发现NetNopologySuite中的几何类型在对象本身上具有SRID属性,并且设置它可以使事情起作用。 e.g。

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

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

答案 2 :(得分:1)

不是答案,而是问题; - )

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

默认(因为该点是几何)是0并且在尝试将LocationLog.Location属性保持为地理位置时会出现SQL错误。 0不是sql地理字段的有效SRID。您需要在sys.spatial_reference_systems视图中指定一个。

  • 你试过没有Fluent NHibernate吗?

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

答案 3 :(得分: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));

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

答案 4 :(得分: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();

必须传递新的CustomType(typeof(MsSql2008GeographyType),null),否则你会得到你太熟悉的“System.ArgumentException:24204”。

只是花了整整一夜才想出那个。