22

我正在尝试将 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 必须与 sys.spatial_reference_systems 目录视图中显示的支持的 SRID 之一匹配。System.ArgumentException: 在 Microsoft.SqlServer.Types.SqlGeography.set_Srid(Int32 值) 在 Microsoft.SqlServer.Types.SqlGeography.Read(BinaryReader r) 在 SqlGeography::.DeserializeValidate(IntPtr, Int32, CClrLobContext*)

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

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

4

5 回答 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 可能有效并且它对我有用(我插入了一些点并在数据库中验证了它)。我还读到最好为地理编写 SQL 查询,以便您可以使用特殊的 SQL 2008 空间方法(而不是使用标准)。

于 2010-10-25T04:40:30.407 回答
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) 的受保护方法 - 它一定是有原因的!

于 2009-11-24T21:37:45.713 回答
1

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

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

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

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

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

于 2009-10-07T07:55:26.397 回答
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”。

只是花了一整晚才弄清楚那个。

于 2012-03-04T02:12:57.973 回答
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 框架中的工厂方法来创建没有 Default 外观的新几何图形。

于 2011-04-20T14:14:33.820 回答