In Linq to NHibernate I'm trying to return businesses within a certain distance of a user. Here is what I have so far:
var query = from b in ActiveRecordLinq.AsQueryable<Business>()
where (3959 * Math.Acos(Math.Cos((Math.PI * coordinates.Latitude / 180)) * Math.Cos((Math.PI * b.Latitude / 180))
* Math.Cos((Math.PI * b.Longitude / 180) - (Math.PI * coordinates.Longitude / 180))
+ Math.Sin((Math.PI * coordinates.Latitude / 180)) * Math.Sin((Math.PI * b.Latitude / 180)))) <= radiusInMiles
orderby b.Name ascending
select b;
return query.ToList();
Unfortunately, it seems that the C# Math class isn't supported in Linq to NHibernate so it gives me the following error:
The method Cos is not implemented
How would I get around this?
Thanks!
Justin
You can do three things:
Implement it and submit a patch to NHibernate so that everybody can use your implementation
Create a failing unit test that isolates the problem and submit it to NHibernate Jira and wait until somebody else implements it.
Do not use Linq, but plain old sql or mixed hql for this query.
You will make some people happy when you choose option 1.
You can't use arbitrary .Net functions in server-side Linq queries.
You can use server-side functions with HQL.
Related
I have a delicate dilemma with follwing SQL statement in Bigquery:
ROUND(SUM(r.DeliveredQuantity * IFNULL(a.DirectCost,a.PurchasePrice))) AS TotalCost,
I need to change it to check if some articles are present or not and if they are, I have to do one expressiona and if not another expression.This is my check
IF(a.ArticleNumber NOT IN ("204","204.2","204.3","204.4","204.5","204.6","204.7")
If those articles are not present then I have to run following query:
ROUND(SUM(r.DeliveredQuantity * IFNULL(a.DirectCost,a.PurchasePrice)))
Otherwise ( and here is where the unfortunate part comes in I guess ) I have to run something like this:
ROUND(SUM(r.DeliveredQuantity * IFNULL(a.DirectCost,a.PurchasePrice) / (a.SalesPrice * i.CurrencyRate)))
So the whole code snippet I have so far is:
IF(a.ArticleNumber NOT IN ("204","204.2","204.3","204.4","204.5","204.6","204.7"),
ROUND(SUM(r.DeliveredQuantity * IFNULL(a.DirectCost,a.PurchasePrice))),
ROUND(SUM(r.DeliveredQuantity * IFNULL(a.DirectCost,a.PurchasePrice) / (a.SalesPrice * i.CurrencyRate)))
) AS TG,
The result is a error saying:
division by zero: 0 / 0
The IFNULL I have to run unfortunately since my users have not be consistent in their data input. But even when only using one of either choices inside the IFNULL, I get the same response saying division by zero: 0/0
Endresult is that IF certaina rticles are present, then I need to get those including the i.CurrencyRate, otherwise without i.CurrencyRate. Any ideas?
PS! I followed this tutorial
IF(a.ArticleNumber NOT IN ("204","204.2","204.3","204.4","204.5","204.6","204.7"),
ROUND(SUM(r.DeliveredQuantity * IFNULL(a.DirectCost,a.PurchasePrice))),
ROUND(SUM(SAFE_DIVIDE((r.DeliveredQuantity * IFNULL(a.DirectCost,a.PurchasePrice)) , (a.SalesPrice * i.CurrencyRate))))
) AS TG,
I am using Grails 2.1.1 and have to find all nearest locations for a given point. My code is looking like this (works in my app):
def findNearLocations(double latitude, double longitude) {
def locationsFromQuery = Location.executeQuery(
"SELECT id,(6371 * 2 * ASIN(SQRT(POWER(SIN((:ulatitude - abs(latitude)) * pi()/180 / 2),2) +" +
"COS(:ulatitude * pi()/180 ) * COS(abs(latitude) * pi()/180) *" +
"POWER(SIN((:ulongitude - longitude) * pi()/180 / 2), 2))))*1000 as distance " +
"FROM Location WHERE is_public = TRUE ORDER BY distance", // HAVING distance < 1000
[ulatitude: latitude.toString().toDouble(), ulongitude: longitude.toString().toDouble()])
// do stuff with locationsFromQuery
}
The formula for the computation of the nearest locations I used for is this stack overflow post but I cannot use the HAVING clause like in the comment. If I use it, I get an hql.hibernate exception, saying, that there is an unexpected identifier HAVING. But why this is working in nearly all examples in google but not working for me?
I am using the h2 database in the memory.
I have some older methods using sql strings and connections that I'm trying to convert to Linq to Entities.
I have rewritten the sql to an ef query as follows;
Using ctx As New DataEntities()
Dim station As String = (From sta In ctx.weather_stations
Let distance = SqlFunctions.SquareRoot(Math.Pow(69.1 * (sta.latitude - lat), 2) + Math.Pow(69.1 * (longi - sta.longitude) * SqlFunctions.Cos(sta.latitude / 57.3), 2))
Where distance < withinRange
Order By distance
Select sta.station_id).Take(1).ToString()
If Not String.IsNullOrEmpty(station) Then
Return station
Else
Return String.Empty
End If
End UsingData
This gives an error,
LINQ to Entities does not recognize the method 'Double Sqrt(Double)' method, and this method cannot be translated into a store expression.
Can this query be done in Linq to EF? If so, how can I reconstruct this query to work?
Could anyone tell me how to use an sql 'AS' statement in a CDBCriteria query?
Whatever i have tired just brings back the columns names of my table in an array and no sign of my sql alias.
I think i may have to add it into my model class but im not sure where to declare it after several attempts to add it in.
Here is mine, as you can see 'distance' is my alias:
$criteria= new CDbCriteria;
$criteria->select='*, 3963 * acos(cos(radians('.$distanceString['latitude'].')) * cos(radians(latitude)) * cos(radians('.$distanceString['longitude'].') - radians(longitude)) + sin(radians('.$distanceString['latitude'].')) * sin(radians(latitude))) AS distance';
$criteria->condition=$sqlCondition;
$criteria->params=$sqlVariables;
$criteria->order='distance';
Thanks for any tips or help in advance! :)
Do you use this with a CActiveDataProvider for an active record class? If so, try defining distance in that class.
Use CDbCommand instead
$rawData=Yii::app()->db->createCommand()
->select('*, 3963 * acos(cos(radians('.$distanceString['latitude'].')) * cos(radians(latitude)) * cos(radians('.$distanceString['longitude'].') - radians(longitude)) + sin(radians('.$distanceString['latitude'].')) * sin(radians(latitude))) AS distance')
->from('TableName')
->where($sqlCondition)
->order('distance')->queryAll(true,$sqlVariables);
eg. together with CArrayDataProvider
$dataProvider=new CArrayDataProvider($rawData);
// $dataProvider->getData() will return a list of arrays.
This is dragging at my nerves!
Scenario:
I am using the geocoder plugin: http://github.com/alexreisner/geocoder/
I have two models: Address and Item
the latitude and the longitude are in Address and an Item belongs_to :address
Now, when I try to do a near search:
Item.near(Person.first.address.coordinates, 20)
on an Item it fails with the following SQL:
Unknown column 'latitude' in 'field list':
SELECT *, 3956 * 2 * ASIN(SQRT(POWER(SIN((51.3883 - latitude) * PI() / 180 / 2), 2) + COS(51.3883 * PI()/180) * COS(latitude * PI() / 180) * POWER(SIN((6.65326 - longitude) * PI() / 180 / 2), 2) )) AS distance FROM `items` WHERE ((latitude BETWEEN 51.0984449275362 AND 51.6781550724638 AND longitude BETWEEN 6.188777824785 AND 7.117742175215) AND (`items`.`accepted` IS NULL AND `items`.`taken_by` IS NULL)) ORDER BY distance ASC
Don't look at the weird Math stuff in the query,
the problem lies within the FROM and the WHERE clause because
the latitude and the longitude attributes are part of the address table,
so a simple addition to the Query would solve the problem:
... FROM items, addresses WHERE ...
... null)) AND items.address_id = addresses.id ORDER BY ...
I just want to add a table to the FROM field and a condition :(
I tried using several named_scopes using :include and :joins, but none worked!
Does anybody know a solution to this? How could I insert this into a scoped ActiveRecord object?
So the Item has address(es) and that's where the longitude and latitude actually exist, right? That's where I think the query is going wrong for you. You could try adding a :joins=>:address ... but I like the following better:
Since all the math occurs in the database, I think you could do:
Address.near(Person.first.address.coordinates, 20)
and then get the items that the addresses belong to, maybe even an :include=>:item or something.