Jadi, Menggunakan saran Phil, saya menulis ulang banyak ini menggunakan spasial. Ini bekerja dengan baik, Anda hanya perlu .NET4.5, EF5+ dan sql server (2008 dan di atas saya percaya). Saya menggunakan EF6 + Sql Server 2012.
Penyiapan
Langkah pertama adalah menambahkan Geography
kolom ke database saya EventListings
tabel (Klik kanan padanya -> Desain). Saya menamai lokasi saya:
Selanjutnya, karena saya menggunakan EDM dengan database terlebih dahulu, saya harus memperbarui model saya untuk menggunakan bidang baru yang saya buat. Kemudian saya menerima kesalahan tentang tidak dapat mengonversi Geografi menjadi ganda, jadi yang saya lakukan untuk memperbaikinya adalah memilih properti Lokasi di entitas, buka propertinya dan ubah jenisnya dari ganda menjadi Geography
:
Meminta dalam Radius &Menambahkan Acara Dengan Lokasi
Maka yang harus Anda lakukan adalah menanyakan koleksi entitas Anda seperti ini:
var events = EventRepository.EventListings
.Where(x => x.Location.Distance(originCoordinates) * 0.00062 <= radiusParam);
Metode ekstensi Jarak mendapatkan jarak dari objek saat ini, ke objek "lain" yang Anda lewati. Objek lain ini bertipe DbGeography
. Anda cukup memanggil metode statis dan metode tersebut akan membuat salah satu anak anjing ini, lalu masukkan Bujur &Lintang Anda ke dalamnya sebagai titik:
DBGeography originCoordinates = DBGeography.fromText("Point(" + originLongitude + " " + originLatitude + ")");
Ini bukan cara saya membuat OriginCoordinates saya. Saya mengunduh database terpisah yang memiliki daftar semua kode pos dan Lintang &Bujurnya. Saya menambahkan kolom tipe Geography
untuk itu juga. Saya akan menunjukkan caranya di akhir jawaban ini. Saya kemudian menanyakan konteks kode pos untuk mendapatkan objek DbGeography dari bidang Lokasi di tabel Kode Pos.
Jika pengguna menginginkan asal yang lebih spesifik daripada sekadar kode pos, saya melakukan panggilan ke Google Maps API (GeoCode untuk lebih spesifik) dan mendapatkan garis lintang dan bujur untuk alamat spesifik pengguna melalui layanan web, dan membuat objek DBGeografi dari nilai Lintang &Bujur dalam respons.
Saya menggunakan Google API saat membuat acara juga. Saya baru saja mengatur variabel lokasi seperti ini sebelum menambahkan entitas saya ke EF:
someEventEntity.Location = DBGeography.fromText("Point(" + longitudeFromGoogle+ " " + latitudeFromGoogle + ")");
Tips &Trik &Pemecahan Masalah Lainnya
Bagaimana saya mendapatkan Metode Perpanjangan Jarak?
Untuk mendapatkan metode ekstensi Distance
Anda harus menambahkan referensi ke proyek Anda:System.Data.Entity
Setelah Anda melakukannya, Anda harus menambahkan using:using System.Data.Entity.Spatial;
ke kelas Anda.
Distance
metode ekstensi mengembalikan jarak dengan satuan ukuran meter (Saya pikir Anda dapat mengubahnya, tetapi ini default). Di sini, parameter radius saya adalah dalam mil, jadi saya melakukan beberapa perhitungan untuk mengonversi.
Catatan :Ada DBGeography
kelas di System.Data.Spatial
. Ini adalah yang salah dan itu tidak akan berhasil untuk saya. Banyak contoh yang saya temukan di internet menggunakan yang ini.
Cara mengonversi Lintang/Bujur ke Kolom Geografi
Jadi, jika Anda seperti saya dan mengunduh basis data kode pos dengan semua Latitude
&Longitude
kolom, dan kemudian menyadari bahwa itu tidak memiliki kolom Geografi... ini mungkin membantu:
1) Tambahkan kolom Lokasi ke tabel Anda. Setel jenisnya ke Geografi.
2) Jalankan sql berikut
UPDATE [ZipCodes]
SET Location = geography::STPointFromText('POINT(' + CAST([Longitude] AS VARCHAR(20)) + ' ' + CAST([Latitude] AS VARCHAR(20)) + ')', 4326)
Cara melihat detail item Geografi
Jadi, ketika Anda menanyakan tabel EventListings Anda di Sql Server Management Studio setelah Anda memasukkan beberapa item DbGeography, Anda akan melihat Location
kolom memegang nilai hex seperti:0x1234513462346. Ini tidak terlalu membantu jika Anda ingin memastikan nilai yang benar dimasukkan.
Untuk benar-benar melihat garis lintang &bujur dari bidang ini, Anda harus menanyakannya seperti ini:
SELECT Location.Lat Latitude, Location.Long Longitude
FROM [EventListings]