NHibernate.Spatial and Sql 2008 Geography type - How to configure

后端 未结 5 1595
你的背包
你的背包 2020-12-13 07:02

I am trying to use Nhibernate with the Sql 2008 Geography type and am having difficulty. I am using Fluent Nhibernate to configure which I am fairly new to so that may be th

相关标签:
5条回答
  • 2020-12-13 07:30

    I know this hardly be useful but in any case. After implementing all lain had said do use in your HQL queries SetParameter third IType parameter. Meaning in

     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) must be passed or you get your all too famililar "System.ArgumentException: 24204".

    Just spent whole night figuring that one out.

    0 讨论(0)
  • 2020-12-13 07:31

    Not really an answer but questions ;-)

    • Are you setting a SRID on the GisSharpBlog.NetTopologySuite.Geometries.Point object?

    The default (since the point is a geometry) is 0 and will give you a SQL error when trying to persist the LocationLog.Location property as a geography. 0 is not a valid SRID for sql geography fields. You will need to specify one from the sys.spatial_reference_systems view.

    • Have you tried without Fluent NHibernate?

    To eliminate as many components from the problem.

    0 讨论(0)
  • 2020-12-13 07:35

    I am in the same boat, and thanks to your start I got it working (inserting and reading spatial data). For anyone else who is interested, firstly the GisSharpBlog.NetTopologySuite.Geometries.Point class is in NetTopologySuite.dll which is part of the nHibernate.Spatial download.

    Secondly, as per James point, make sure you set the SRID to 4326.

    And lastly, the map needs to look like this:

    Map(a => a.Location).CustomType(typeof(NHibernate.Spatial.Type.GeometryType));
    

    I am using Geography, but I read somewhere that using GeometryType may work and it does for me (I inserted some points and verified it in the database). I also read that its best to write SQL Query's for Geography so that you can use the special SQL 2008 Spatial methods (as opposed to using Criteria).

    0 讨论(0)
  • 2020-12-13 07:40

    Steve is right, you need to explicitly set a SRID for your geometry type. Looking at the NHibernate.Spatial source (which you can checkout using SVN or whatever), doing a search for SRID comes up with this buried in the code as a comment hint:

    <class name="MyGeoTableA">
        <property name="MyGeoColumn">
            <type name="NHibernate.Spatial.Type.GeometryType, NHibernate.Spatial">
                <param name="srid">1234</param>
            </type>
        </property>
    </class>
    

    It looks like you need to set a parameter named SRID to whatever number you need (look it up in a SRID table). Obviously this is old-school XML configuration but fluent will have a method somewhere to add key/value string parameters. Give that a try.


    Edit

    After a bit more research, I found that trying to set a srid attribute on a column failed NHibernate's XML mapping validation, it throws an XmlSchemaValidationException. Instead, I found that geometry types in NetNopologySuite have a SRID attribute on the object themselves, and setting this makes things work. e.g.

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

    There must be a better way to do this though (configure it instead of setting it all the time) but I haven't worked that out yet. If you look inside MsSql2008GeometryType class, it has a protected method called SetDefaultSRID(IGeometry) - it must be there for a reason!

    0 讨论(0)
  • 2020-12-13 07:40

    You can create your own factory with a default SRID. For example, you can create a facade for factories such as this:

    public static class Default
    {
        private const int DefaultSrid = 4326;
    
        public static readonly IGeometryFactory Factory;
    
        static Default()
        {
            Factory = new GeometryFactory(new PrecisionModel(), DefaultSrid);
        }
    }
    

    and use it like this:

    var point = Default.Factory.CreatePoint(new Coordinate(10, 10));
    

    instead of using the "new" keyword. You can also use the Default.Factory as a factory method in your IoC framework to create new geometries without the Default facade.

    0 讨论(0)
提交回复
热议问题