Search code examples
nhibernatespatialfluent-nhibernate-mapping

NHibernate Spatial Mapping returns Antrl error


I am using NHibernate 3.3. I have a case where I want to insert a calculated column which is not referenced.

My Domain Entity can be reduced to the form

    public class Location
    {
         public virtual IPoint GeoLocation {get;set;}
    }

    public class MappingOverride : IAutoMappingOverride<Location>
    {
        public void Override(AutoMapping<Location> mapping)
        {
            mapping
              .Map(e => e.GeoLocation)
              .Column("GeoLocation")
              .CustomSqlType("geography")
               .CustomType<MsSql2008GeographyType>;
        }
    }

The table column is of type 'Geography`

However it errors out as

   at System.Reflection.RuntimeAssembly.GetExportedTypes(RuntimeAssembly assembly, ObjectHandleOnStack retTypes)
   at System.Reflection.RuntimeAssembly.GetExportedTypes()
   at GeoAPI.GeometryServiceProvider.GetLoadableTypes(Assembly assembly)
   at GeoAPI.GeometryServiceProvider.ReflectInstance()
   at GeoAPI.GeometryServiceProvider.get_Instance()
   at NetTopologySuite.Geometries.Geometry.set_SRID(Int32 value)

It says that it needs Antrl.Runtime, but a very old version. All the Antrl.Runtime nuget packages out there have a different assembly identifier.

Could not load file or assembly 'antlr.runtime, Version=2.7.6.2, Culture=neutral, PublicKeyToken=1790ba318ebc5d56' or one of its dependencies. The system cannot find the file specified.

I worked on a separate project where I used map by code convention and it works without any reference to Antrl.Runtime.

Need help to point myself in the right direction...


Solution

  • As a separate sample project I tried something which worked, WHICH DID NOT WORK in the actual ASP.NET MVC project.

    Definition of Class

    public class Location : IEntity
    {
        public virtual int Id { get; protected set; }
    
        public virtual string LocationName { get; set; }
    
        public virtual IPoint GeoLocation { get; set; }
    }
    

    Mapping

    public class LocationMapping : IAutoMappingOverride<Location>
    {
        public void Override(AutoMapping<Location> mapping)
        {
            mapping.Map(x => x.LocationName).Column("Name");
            mapping.Map(x => x.GeoLocation).Column("GeoLocation")
                   .CustomType<MsSql2008GeographyType>();
        }
    }
    

    Test

    public class WhenSavingGeoLocation : BasePersistanceTest
        {
            [Test]
            public void Save()
            {
                this.Session
                 .SaveOrUpdate(new Location { 
                       LocationName = "Category 01", 
                       GeoLocation = new Point(-72.12, 32.2323234) {  SRID = 4326 } 
                });
            }
        }
    

    NHibernate.Spatial uses NetTopologicalSuite which itself is a derivative of GeoAPI The GeoAPI library defines an interface GeoAPI.Geometries and while loading / searching the correct implementation in the current project was failing with the Antlr error in the MVC project.

    It was however able to fetch the NetTopologySuite.NtsGeometryServices implementation in the separate sample project. The actual code in GeoAPI which searches for the implementation goes like

           private static IGeometryServices ReflectInstance()
            {
    #if !PCL
                var a = AppDomain.CurrentDomain.GetAssemblies();
                foreach (var assembly in a)
                {
                    // Take a look at issue 114: http://code.google.com/p/nettopologysuite/issues/detail?id=114
                    if (assembly is System.Reflection.Emit.AssemblyBuilder) continue;
                    if (assembly.GetType().FullName == "System.Reflection.Emit.InternalAssemblyBuilder") continue;
                    if (assembly.GlobalAssemblyCache && assembly.CodeBase == Assembly.GetExecutingAssembly().CodeBase) continue;
    
                    foreach (var t in GetLoadableTypes(assembly))
                    {
                        if (t.IsInterface) continue;
                        if (t.IsAbstract) continue;
                        if (t.IsNotPublic) continue;
                        if (!typeof(IGeometryServices).IsAssignableFrom(t)) continue;
    
                        var constuctors = t.GetConstructors();
                        foreach (var constructorInfo in constuctors)
                        {
                            if (constructorInfo.IsPublic && constructorInfo.GetParameters().Length == 0)
                                return (IGeometryServices)Activator.CreateInstance(t);
                        }
                    }
                }
    #endif
                throw new InvalidOperationException("Cannot use GeometryServiceProvider without an assigned IGeometryServices class");
            }
        }
    

    This gets called when setting the SRID on the geometry. I am guessing that my MVC project has a reference to an assembly which makes this look for Antlr. There were some suggestions of adding a redirect for to newer Antlr assembly. I tried that as well but the error still kept repeating.