공간을 사용하여 우편 번호 반경을 검색하려면 어떻게합니까?

c# entity-framework entity-framework-6 sql-server-2012

문제

배경

특정 우편 번호 반경 내에서 이벤트를 찾는 응용 프로그램을 작성하고 있습니다. 티켓 마스터처럼 우편 번호를 입력하고 반경 x에있는 모든 콘서트를 표시하는 것처럼 생각할 수 있습니다.

우편 번호가있는 데이터베이스 테이블과 각 우편 번호가 위도와 경도입니다. 또한 각 '이벤트'ZipCode 필드가있는 'EventListings'테이블이 있습니다.

문제

현재, 서비스 계층의 Linq-to-Entities 쿼리에서 Haversine 수식을 사용하여 반경 내에있는 이벤트를 찾습니다. 지금은 where 절의 필터로 사용하고 있습니다. 나는 또한 select 절에 넣고 싶습니다. 그래서 웹 사이트에서 "이것은 4.6 마일 떨어져 있습니다"라고 표시 할 수 있습니다.

Linq-to-Entities가 SQL로 변환 할 수 없다는 불평을하기 때문에이 코드를 별도의 C # 메서드로 옮길 수 없기 때문에 select 문에 전체 수식을 복사하는 것으로 끝납니다. 이것은 매우 추한 것입니다. 나는 그것을 고치려고 노력했다.

나는 무엇을 시도 했는가?

엔티티를 편집하고 "DistanceFromOrigin"이라는 특수 스칼라 속성을 추가했습니다. 그런 다음 모든 엔티티 데이터를 가져온 저장 프로 시저와 새로운 필드 "DistanceFromOrigin"에 대한 하드 코딩 된 값 (테스트 용)을 만들었습니다.

그런 다음 EventListings 엔터티에 대한 선택 진술을 위해 sproc을 사용하도록 엔티티 프레임 워크에 지시 할 수 없다는 사실을 깨닫게되었습니다. Phil은 내가 제안한 공간을 제안 했으므로 나도 함께갔습니다.

문제

Spatial을 사용하여 우편 번호 반경 내에서 이벤트를 검색하려면 어떻게해야합니까?

수락 된 답변

그래서 Phil의 제안을 사용하여 공간을 사용하여 많은 것을 다시 작성했습니다. 이것은 훌륭하게 작동했지만, .NET4.5, EF5 + 및 SQL 서버 (2008 년 이상)가 필요합니다. 나는 EF6 + Sql Server 2012를 사용하고 있습니다.

설정

첫 번째 단계는 내 데이터베이스 EventListings 테이블에 Geography 열을 추가하는 것입니다 (마우스 오른쪽 버튼으로 클릭 -> 디자인). 나는 광산 위치라는 :

여기에 이미지 설명을 입력하십시오.

다음으로, 먼저 데이터베이스와 함께 EDM을 사용하기 때문에, 내가 만든 새 필드를 사용하도록 모델을 업데이트해야했습니다. 그런 다음 지리를 두 배로 변환 할 수 없다는 오류가 발생했습니다. 따라서이 문제를 해결하기 위해 엔티티에서 Location 속성을 선택하고 해당 속성으로 이동하여 유형을 Double에서 Geography 변경했습니다.

여기에 이미지 설명을 입력하십시오.

반경 내에서 쿼리하기 및 위치로 이벤트 추가하기

다음과 같이 엔티티 컬렉션을 쿼리하면됩니다.

 var events = EventRepository.EventListings
                             .Where(x => x.Location.Distance(originCoordinates) * 0.00062 <= radiusParam); 

거리 확장 메서드는 현재 개체에서부터 전달되는 "다른"개체까지의 거리를 가져옵니다.이 개체는 DbGeography 유형 DbGeography . 방금 정적 메서드를 호출하고이 강아지 중 하나를 만든 다음 경도 및 위도를 점으로 던지십시오.

DBGeography originCoordinates = DBGeography.fromText("Point(" + originLongitude + " " + originLatitude + ")");

이 방법으로 내 originCoordinates를 만든 방법이 아닙니다. 나는 모든 우편 번호와 위도 및 경도 목록이있는 별도의 데이터베이스를 다운로드했습니다. 나는 Geography 타입의 칼럼을 추가했다. 나는이 대답의 끝에서 어떻게 보여줄 것인가. 그런 다음 Zipcode 컨텍스트를 쿼리하여 ZipCode 테이블의 Location 필드에서 DbGeography 개체를 가져 왔습니다.

사용자가 우편 번호 이외의 특정 출처를 원한다면 Google Maps API (GeoCode가 더 구체적 임)를 호출하고 웹 서비스를 통해 사용자 고유 주소의 위도와 경도를 가져 와서 DBGeography 객체를 만듭니다. 응답의 위도 및 경도 값

이벤트를 만들 때 Google API를 사용합니다. EF에 엔티티를 추가하기 전에 위치 변수를 다음과 같이 설정했습니다.

someEventEntity.Location = DBGeography.fromText("Point(" + longitudeFromGoogle+ " " + latitudeFromGoogle + ")");

기타 팁 및 트릭 및 문제 해결

Distance Extension Method는 어떻게 얻었습니까?

확장 메서드 Distance 를 얻으려면 프로젝트에 대한 참조를 추가해야합니다. System.Data.Entity 작업을 수행 한 후에 using : using System.Data.Entity.Spatial; 추가해야합니다 using System.Data.Entity.Spatial; 수업 시간에.

Distance 확장 메서드는 미터 단위로 거리를 반환합니다 (생각하면 변경할 수 있지만 기본값 임). 여기, 내 반지름 매개 변수는 마일 단위이므로 변환 할 수학을했습니다.

참고 : System.Data.Spatial DBGeography 클래스가 있습니다. 이것은 잘못된 것이고 그것은 나를 위해 작동하지 않을 것입니다. 인터넷에서 발견 된 많은 예제가이 예제를 사용했습니다.

위도 / 경도를 지리 열로 변환하는 방법

그래서, 당신이 나를 좋아하고 모든 LatitudeLongitude 열이있는 zipcode 데이터베이스를 다운로드 한 다음 지리 열이 없다는 것을 알게되면 ... 도움이 될 수 있습니다.

1) 테이블에 위치 컬럼을 추가하십시오. 유형을 지역으로 설정하십시오.

2) 다음 SQL을 실행합니다.

UPDATE [ZipCodes]
SET Location = geography::STPointFromText('POINT(' + CAST([Longitude] AS VARCHAR(20)) + ' ' + CAST([Latitude] AS VARCHAR(20)) + ')', 4326)

지리 항목의 세부 정보를 보는 방법

따라서 일부 DbGeography 항목을 삽입 한 후 Sql Server Management Studio에서 EventListings 테이블을 쿼리하면 Location 열에 0x1234513462346과 같은 16 진수 값이 저장됩니다. 올바른 값을 삽입하고 싶을 때 유용하지는 않습니다.

이 필드의 위도와 경도를 실제로 보려면 다음과 같이 쿼리해야합니다.

SELECT Location.Lat Latitude, Location.Long Longitude
FROM [EventListings]


아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow
이 KB는 합법적입니까? 예, 이유를 알아보십시오.
아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow
이 KB는 합법적입니까? 예, 이유를 알아보십시오.