Вводные и примерные данные
Прежде всего, я хочу извиниться за неопределенный заголовок c. Поскольку я потратил много времени на решение этой проблемы (Google, SO, пробная версия и ошибка), я пришел к тому, что даже не знаю, близок ли я к решению или нет.
Моя основная проблема c: я хочу создать REST-Api с. NET Ядром, которое возвращает объекты на определенном расстоянии от пользователя.
SQL
Предположим, у меня есть таблица с именем Музеи , которая имеет следующие столбцы:
+------------+---------------+
| name | type |
+------------+---------------+
| Id | int |
| MuseumName | nvarchar(max) |
| Location | geography |
+------------+---------------+
Модель
Принадлежность. NET Основная модель выглядит следующим образом:
public class MuseumModel
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string MuseumName { get; set; }
[JsonIgnore]
public Geometry Location { get; set; }
}
Проблема
Теперь я хочу создать REST-Api, который возвращает музеи в зависимости от местоположения пользователя и максимального расстояния. Давайте предположим, что вызов API такой: Museums/ByLocation?Latitude=50.114034&Longitude=8.679355&distance=1000
. Элементы, возвращаемые с JSON, должны содержать Id , MuseumName и Distance . В дополнение к этому, они должны быть упорядочены по расстоянию .
Основная проблема : Где я должен вычислить эти данные о местоположении. На мой взгляд, есть 3 теоретических варианта, в которых можно выполнять вычисления:
- SQL
- REST-Api
- Native Client (на мой взгляд это на самом деле это не вариант, потому что мне нужно было бы сначала перенести все музеи)
До сих пор я пытался выполнять вычисления с сервером SQL. Есть ли какие-либо аргументы против этого?
Идея A (logi c на контроллере, вычисления на БД)
Прежде всего я попытался решить проблему в контроллере REST-Api:
var geometryFactory = NtsGeometryServices.Instance.CreateGeometryFactory(srid: 4326);
Geometry userLocation = geometryFactory.CreatePoint(new Coordinate(longitude, latitude));
return await _context.Museums
.Where(x => x.Location.IsWithinDistance(userLocation, distance))
.OrderBy(x => x.Location.Distance(userLocation))
.ToListAsync();
Задача A.1) : Я спрашиваю себя, является ли здесь оптимальным время вычислений, поскольку IsWithinDistance
и Distance
вызываются отдельно. Оптимизирует ли сервер SQL этот запрос?
Проблема A.2) : Как я могу легко добавить Distance к полученному JSON? В этом примере расстояние выбрасывается после вычисления.
Идея B (хранимая процедура, вызываемая контроллером)
Мой второй подход был хранимой процедурой на сервере SQL, которая в основном добавляет поле DistanceToUser
для оператора SELECT. SP выглядит следующим образом:
CREATE PROCEDURE [dbo].[MuseumsWithDistanceToUser]
@latitude float,
@longitutde float
AS
DECLARE @userLocation geography;
SET @userLocation = geography::STGeomFromText('POINT('+CONVERT([varchar](20),@longitutde)+' '+CONVERT([varchar](20),@latitude)+')', 4326);
SELECT *, DistanceToUser = Location.STDistance(@userLocation) FROM [dbo].[Museums]
GO
С этим подходом я думаю, что решил проблему A.1, потому что вычисления должны быть оптимизированы. Полученная таблица теперь содержит столбец DistanceToUser
, но, к сожалению, возникла новая проблема ...
Проблема B.1) : новая проблема заключается в том, что я не могу разыграть данные в модель. Я даже создал новую модель MuseumWithDistanceToUserModel : MuseumModel
с атрибутом DistanceToUser
, но такой подход привел к этой ошибке , а добавление атрибута [NotMapped]
невозможно, поскольку в основном новая модель сопоставлена с SP.
Если вы думаете, что это путь к go, я могу поделиться кодом и возникающими проблемами. Но действительно ли это хорошее решение?
Заключение
Я знаю, что мог бы делать операторы WHERE и ORDER BY в хранимой процедуре и создавать новую модель без какого-либо наследования. Но это кажется мне не совсем чистым. В дополнение к этому я все еще хочу иметь возможность манипулировать запросом на контроллере. Редактирование SP на БД каждый раз, когда необходима корректировка, не является предпочтительным. Пожалуйста, поделитесь своими мыслями по этому поводу. Я благодарен за все:)