2017-01-19 2 views
0

Ich versuche, meinen Adressstandort abzufragen, um Adressen zu ermitteln, die sich innerhalb des spezifischen Bereichs befinden Radius. Unten ist mein where-Klausel und results ist ein IEnumerable<Properties>NHibernate-Ausnahme: Das Objekt des Typs 'NHibernate.Hql.Ast.HqlParameter' kann nicht in den Typ 'NHibernate.Hql.Ast.HqlBooleanExpression' umgewandelt werden.

Func<Address, bool> predicate = l => 
{ 
    if (l.Location == null && l.Longitude.HasValue && l.Latitude.HasValue) 
    { 
     var point = new Point(l.Longitude.Value, l.Latitude.Value); 
     return point.Distance(p) <= 300; 
    } 
    return false; 
    }; 

    results = results.Where(x => predicate(x.Address)); 

Allerdings bin ich eine Ausnahme von NHibernate als

bekommen

„Kann nicht das Objekt des Typs‚NHibernate.Hql.Ast.HqlParameter‘werfen eingeben 'NHibernate.Hql.Ast.HqlBooleanExpression'.

Wie kann ich dieses Problem beheben?

Jede Hilfe ist sehr APPRE zitiert.

+0

Ich würde vermuten, dass NHibernate Ihr Prädikat in Ihrer Datenbank über SQL nicht ausführen kann. Versuchen Sie einige einfache Typen zu verwenden, die NHibernate in sql übersetzen kann. – Rabban

+0

Einfache Typen im Sinne? Du meinst hier 'Point' Typ? – Karthik

+0

Etwas, das Ihre Datenbank versteht. Was sind die Arten von 'Longitude' und' Latitude'? Ist es möglich, die 'point.Distance (p)' Berechnung selbst vorzunehmen? Ich weiß nicht, wie die 'Distance()' Methode funktioniert, aber vielleicht kannst du etwas wie 'l.Longitude => 300 &&Longitude <= 300' machen. – Rabban

Antwort

0

Sie müssen LINQ-Ausdrücke, nicht Lambdas verwenden! Versuchen Sie stattdessen:

Expression<Func<Address, bool>> predicate = ... 
+1

Nicht genug ... Das Lambda ist ein mehrzeiliges Lambda, das einen Codeblock verwendet. Mir ist kein Linq-Provider bekannt, der damit umgehen könnte. –

+0

Sie haben Recht, ich stimme Ihnen zu. –

0

Ihr Filterausdruck nicht zu SQL übersetzt werden kann. Es ist ein mehrzeiliger Ausdruck. , wie jeder andere LINQ-Provider von orm, benötigt man ein einfaches liner, das in SQL übersetzt werden kann.

Darüber hinaus verwenden Ihre Filterausdrücke eine Klasse, die eine Berechnung durchführt (Distance() in Ihrem Fall). Der LINQ-Anbieter wird keine Kenntnisse darüber haben, wie dieser in SQL konvertiert werden kann, es sei denn, Sie haben die Nummer extend it. Schreiben Sie Ihr Computing besser in das Lambda, wenn es in einer SQL-übersetzbaren Weise geschrieben werden kann.

Wenn Sie Ihr Prädikat an vielen Stellen benötigen, können Sie eine Funktion schreiben, um es in einer lokalen Variablen zu erhalten, bevor Sie es verwenden.

private Expression<Func<Address, bool>> GetFilterByMaxDistance(double maxDistance) 
{ 
    // replace ??? with your computation, without block of code (no `{}`) nor call to 
    // functions not known for being handled by the LINQ provider 
    return a => ??? <= maxDistance; 
} 

... 

    var predicate = GetFilterByMaxDistance(300); 
    results = results.Where(predicate); 

Ansonsten, wenn Ihre results lokalen Variablen bereits ist ‚ausreichend gefiltert‘ für angemessene Leistungen mit, rufen .AsEnumerable() vor Ihren Filter, diesmal nur als Func<Address, bool>, nicht als Expression<Func<Address, bool>> Anwendung.

Der Aufruf .AsENumerable() vor der Anwendung .Where(predicate) führt dazu, dass Ihr Prädikat im Speicher von .NET-Laufzeit ausgeführt wird, ohne dass es in SQL konvertiert werden muss.
Aber das führt natürlich dazu, dass die Filterung in Ihrer App und nicht in der DB erfolgt.

Verwandte Themen