Я пытаюсь вернуть список предметов, которые находятся, скажем, в 50 милях от заданного местоположения.
Моя таблица (упрощенная) выглядит следующим образом:
У меня есть первоначальный запрос:
var query = db.MyTable.Where(o=> o.Status == "New" && o.Active == true);
query = query.Where(o => new Point(o.Longitude, o.Latitude)
.IsWithinDistance(new Point(_currentLongitude, _currentLatitude), 50));
var result = query.ToList()
Однако - похоже, это не работает, и я получаю сообщение об ошибке, как показано ниже - есть идеи, как это решить? или если есть лучший способ получить ближайшие предметы?
.Where(p => new Point(p.Longitude, p.Latitude) .IsWithinDistance(геометрия: __p_3,
Distance: ___maxDistance_4))' не удалось перевести.Либо перепишите запрос в форме, которую можно перевести, либо явно переключитесь на оценку клиента, вставив вызов AsEnumerable(), AsAsyncEnumerable(), ToList() или ToListAsync(). См. https://go.microsoft.com/fwlink/?linkid=2101038 для получения дополнительной информации.
Запуск.cs:
services.AddDbContext<AppDbContext>(options =>
{
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"),
x => x.UseNetTopologySuite());
});
@RobertHarvey - это встроенная функция в Microsoft.EntityFrameworkCore.SqlServer.NetTopologySuite
. См. Пространственные данные EF Core и Пространственные данные в поставщике SQL Server EF Core
@Steve - Вы добавили .UseNetTopologySuite
, как показано здесь ? (Кроме того, я предполагаю, что SQL Server, пожалуйста, подтвердите или исправьте.)
@MattJohnson-Пинт: пока
Насколько я могу судить, создание нового Point
из широты/долготы на данный момент не поддерживается. Возможно, вам придется хранить ваши данные как тип Point
в вашей модели.
@RobertHarvey привет - да пробовал var xx = query = (IQueryable<Profile>)query.Where(o => new Point(o.Longitude, o.Latitude) .IsWithinDistance(new Point(_profile.Longitude, _profile.Latitude), _maxDistance)).ToList();
но все та же ошибка
@MattJohnson-Pint Да - MS SQL 2019 Express, и да, уже добавлено в startup.cs (отредактировал ответ, чтобы показать, что я включил)
не могли бы вы протестировать первую часть того, где конвертировать в список, а затем запустить второй фильтр db.MyTable.Where(o=> o.Status == "New" && o.Active == true).ToList();.
@coder_b - это нанесет ущерб цели пространственных запросов/индексов на стороне SQL и может привести к ненужному перемещению большого количества данных клиенту. Конечно, все зависит от того, сколько данных мы имеем в виду, но я бы не рекомендовал такой подход.
Я полностью согласен, я проверял, что IsWithinDistance работает должным образом с отключенным набором данных. интересно, исключают ли какие-либо проблемы, связанные с конфигурациями и т. д.
Чтобы эта функция работала, вам необходимо сохранить эти координаты как Point
в поле SQL geography
. Вы можете легко добавить это в существующую модель в качестве вычисляемого столбца для нового свойства.
// on your entity
public Point Coordinates { get; }
// in your db context's OnModelCreating
modelBuilder.Entity<YourEntity>()
.Property(x => x.Coordinates)
.IsRequired()
.HasComputedColumnSql("geography::Point(Latitude, Longitude, 4326)");
Обратите внимание, что SRID 4326 — это широко используемая система координат широта/долгота, поддерживаемая SQL Server. Подробнее об этом здесь.
Создайте свою модель и разверните ее в своей базе данных.
Теперь, когда у вас есть пространственное поле и свойство, вы можете сделать запрос следующим образом:
var point = new Point(_currentLongitude, _currentLatitude) { SRID = 4326 };
var distanceInMeters = 50 * 1609.344; // 50 miles to meters conversion
var results = db.YourEntity
.Where(x => x.Coordinates.IsWithinDistance(point, distanceInMeters))
.ToList();
SRID 4326 использует метры для расстояния, поэтому обязательно конвертируйте, как показано выше, если вы используете мили.
Кроме того, если у вас много данных, вы также захотите добавить пространственный индекс в этот столбец, но EF Core пока не поддерживает это напрямую, поэтому вам придется делать это непосредственно в SQL.
Обратите внимание, что подход с вычисляемым столбцом является необязательным. Вы всегда можете иметь отдельное свойство Point
, но тогда у вас не будет отдельных свойств широты и долготы.
Привет, спасибо за быстрый ответ, я попробую это. Есть ли какая-либо польза от наличия/отсутствия вычисляемого столбца для точки?
Поле Point
(sql geography
) — это необходимые данные для работы пространственных запросов. Вы можете просто заполнить Point
и не включать отдельные поля широты и долготы. Наличие обоих в основном просто удобство.
@MattJohnson-Pint, не могли бы вы взглянуть на это stackoverflow.com/questions/70847958/…
Вам нужно сделать именно так, как предлагает сообщение об ошибке: «Либо перепишите запрос в форме, которую можно перевести, либо явно переключитесь на оценку клиента, вставив вызов либо AsEnumerable(), AsAsyncEnumerable(), ToList() или ToListAsync. (). Дополнительную информацию см. на странице go.microsoft.com/fwlink/?linkid=2101038.