我正在尝试将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以使用可以提供任何见解的空间地理类型的人都将非常感激。
答案 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)
不是答案,而是问题; - )
默认(因为该点是几何)是0并且在尝试将LocationLog.Location属性保持为地理位置时会出现SQL错误。 0不是sql地理字段的有效SRID。您需要在sys.spatial_reference_systems视图中指定一个。
从问题中消除尽可能多的组件。
答案 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”。
只是花了整整一夜才想出那个。