使用NHibernate 3 linq提供程序和NHibernate空间

时间:2012-03-08 06:38:03

标签: linq nhibernate spatial

我开始使用NHibernate 3 linq提供商,这很棒。 到目前为止,我已经将NHibernate空间与Criteria一起使用。

如何在NHibernate空间中使用linq?

谢谢, 罗恩

3 个答案:

答案 0 :(得分:0)

我不知道是否可以开箱即用。要么在linq提供程序中使用NH钩子来实现它,要么就像我在这里发布https://stackoverflow.com/a/9585622/671619

一样

答案 1 :(得分:0)

自从您最初发布问题以来已经过了一段时间,但是,由于您没有将其标记为已回答,请让我向您展示我在该主题上撰写的博文,在HQL中使用NH Spatial显示几个查询示例和LINQ。

您可以查看here

答案 2 :(得分:0)

迟到的回答但是,您可以在LINQ查询中使用NHibernate.Spatial。你必须使用NHibernate.Spatial forks之一(例如:@psousa在这里:https://github.com/pmcxs/Nhibernate.Spatial或@suryapratap在这里https://github.com/suryapratap/Nhibernate.Spatial)。

可以通过查看NHibernate.Spatial.Linq.Functions.SpatialLinqToHqlGeneratorsRegistry的源代码来猜测支持的操作范围。 源文件。例如这里的代码:

public class AnalysisDistanceGenerator : SpatialMethodGenerator<IGeometry, double>
{
    public AnalysisDistanceGenerator() : base(g => g.Distance(null)) { }
}

这意味着您应该可以执行以下查询:

dbSession.Query<Entity>().Where(x => x.Location.Distance(point) < 50).FirstOrDefault();

有一个错误(实际上,这是NHibernate设计中的一个疏忽)导致上面的查询使Point实例失败并出现错误:

ArgumentException: 24204: The spatial reference identifier (SRID) is not valid.

这是因为NHibernate试图找到一个NHibernate IType实例用于将“Point”数据类型(参数)转换为SQL并最终找不到任何内容,因此它使用不遵循SRID参数的默认SerializableType你在点实例上设置了它。

监督是NHibernate本身不允许在其自身注册的默认值之外指定“实体持久性”(作为SQL的类型转换器)。对于加载或保存实体,它使用为从类映射(hbm / xml,fluent或代码映射)编译的实体定义的元数据,因此可以工作,但对于非映射的Point实例,它只是处理它们错误

在NHibernate上花了很多时间调试之后,解决方案只是让NHibernate通过为它注册一个IType来处理Point和IPoint实例,就好像它们是内置类型一样(然后你可以为它定义SRID,子类型)它工作正常。

不幸的是,此方法使用反射来访问标记为private的NHibernate.Type.TypeFactory.RegisterType方法。我无法找到任何公共API来实现此方法。

在创建NHibernate SessionFactory期间(在app启动时)调用此方法一次。显然,它假设您将对未明确设置其SRID的所有点参数使用默认SRID 4326。您可以为参数字典传递null,而不是根据需要指定默认的SRID和子类型。

它很难看,但效果很好:

    static void RegisterGeometryTypeForIPointUsingReflection()
    {
        var methods =
            typeof(TypeFactory).GetMethods(BindingFlags.NonPublic | BindingFlags.Static);

        var requiredOverload = methods.Where(
            x =>
            {
                if (x.Name != "RegisterType") return false;

                var args = x.GetParameters();
                if (args.Length != 2) return false;

                return args[0].ParameterType == typeof(IType)
                       && args[1].ParameterType == typeof(IEnumerable<string>);
            })
            .FirstOrDefault();

        if (requiredOverload == null)
        {
            throw new NotSupportedException(
                "Could not find TypeFactory.RegisterType method overload in NHibernate. Please report this issue.");
        }

        requiredOverload.Invoke(
            null,
            new object[]
            {
                new CustomType(
                    typeof(GeometryType),
                    new Dictionary<string, string>
                    {
                        { "srid", "4326" },
                        { "subtype", "POINT" }
                    }),
                new[]
                { typeof(IPoint).AssemblyQualifiedName, typeof(Point).AssemblyQualifiedName }
            });
    }