Использование NHibernate 3 linq-провайдера с NHibernate пространственной - PullRequest
0 голосов
/ 08 марта 2012

Я начинаю работать с провайдером NHibernate 3 linq, и это здорово.До сих пор я использовал NHibernate пространственный с критериями.

Как мне использовать linq с NHibernate пространственным?

Спасибо, Рон

Ответы [ 3 ]

0 голосов
/ 30 марта 2012

Прошло некоторое время с тех пор, как вы изначально опубликовали вопрос, но, поскольку вы не пометили его как ответивший, позвольте мне показать вам сообщение в блоге, которое я написал по этой теме, с несколькими примерами запросов с использованием NH Spatial в HQL.и LINQ.

Вы можете проверить это здесь

0 голосов
/ 12 ноября 2013

Поздний ответ, но да, вы можете использовать NHibernate.Spatial в запросах LINQ. Вам придется использовать одну из пространственных вилок NHibernate.Spatial (например, одну от @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 и в итоге ничего не находит, поэтому он использует стандартный SerializableType, который не учитывает параметр SRID Вы устанавливаете на сам экземпляр точки.

Недостатком является то, что NHibernate изначально не позволяет задавать «персистентность сущностей» (которые действуют как средства скрытия типов из / в SQL), помимо стандартных, которые поставляются с ним, которые он сам регистрирует. Для загрузки или сохранения сущностей он использует метаданные, определенные для сущности, которая была скомпилирована из сопоставлений классов (hbm / xml, беглый или сопоставление по коду), так что это работает, но для неотображенных экземпляров Point он просто неправильно обрабатывает их .

После многих часов отладки в NHibernate решение состоит в том, чтобы просто заставить NHibernate рассматривать экземпляры Point и IPoint, как если бы они были встроенным типом, зарегистрировав для него IType (а затем вы можете определить SRID, подтип для него) и работает нормально.

К сожалению, этот метод использует отражение для доступа к методу NHibernate.Type.TypeFactory.RegisterType, который помечен как закрытый. Мне не удалось найти общедоступный API для доступа к этому методу.

Просто вызовите этот метод один раз при создании NHibernate SessionFactory (при запуске приложения). Очевидно, что предполагается, что вы будете использовать SRID по умолчанию 4326 для всех точечных параметров, которые явно не устанавливают свои SRID. Вы можете передать значение 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 }
            });
    }
0 голосов
/ 09 марта 2012

я не знаю, возможно ли это из коробки. Либо используйте NH-хуки в провайдере linq для его реализации, либо делайте так, как я написал здесь https://stackoverflow.com/a/9585622/671619

...