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 地理类型 - 如何配置的主要内容,如果未能解决你的问题,请参考以下文章