예, SQL 문자열을 응용 프로그램 코드로 하드 코딩하는 것은 일반적으로 안티 패턴입니다.
생산 코드에서 이것을 보며 수년간 개발 한 공차를 따로 떼어 봅시다. 동일한 파일에서 다른 구문과 완전히 다른 언어를 혼합하는 것은 일반적으로 바람직한 개발 기술이 아닙니다. 이것은 여러 언어에 문맥 적 의미를 부여하도록 설계된 Razor와 같은 템플릿 언어와 다릅니다. Sava B.가 아래 주석에서 언급 했듯이 C # 또는 다른 응용 프로그램 언어 (Python, C ++ 등)의 SQL은 다른 문자열이므로 의미 적으로 의미가 없습니다. 대부분의 경우 하나 이상의 언어를 혼합 할 때도 동일하게 적용되지만 C의 인라인 어셈블리, HTML에서 CSS의 작고 이해하기 쉬운 스 니펫 (CSS는 HTML과 혼합되도록 설계되어 있음)과 같이 수용 가능한 상황이 있습니다. ), 다른 사람.
(로버트 C. Martin은 언어 혼합, Clean Code , 17 장, "코드 냄새 및 휴리스틱 스", 288 페이지)
이 응답을 위해 SQL에 초점을 맞출 것입니다 (질문에서 요청한대로). SQL을 일관된 분리 된 문자열 집합으로 저장할 때 다음과 같은 문제가 발생할 수 있습니다.
- 데이터베이스 논리를 찾기가 어렵습니다. 모든 SQL 문을 찾기 위해 무엇을 검색합니까? "SELECT", "UPDATE", "MERGE"등이있는 문자열?
- 동일하거나 유사한 SQL의 리팩토링 사용이 어려워집니다.
- 다른 데이터베이스에 대한 지원을 추가하는 것은 어렵습니다. 어떻게 이것을 달성 할 수 있습니까? 각 데이터베이스에 대해 if..then 문을 추가하고 모든 쿼리를 메소드에 문자열로 저장합니까?
- 개발자는 다른 언어로 된 문장을 읽고 메소드의 목적에서 메소드의 구현 세부 사항 (데이터 검색 방법 및 위치)으로 초점이 이동함에 따라주의가 산만 해집니다.
- 한 줄짜리 문제는 그다지 큰 문제가되지 않지만 명령문이 더욱 복잡해지면 인라인 SQL 문자열이 분리되기 시작합니다. 113 라인으로 무엇을합니까? 방법에 113 줄을 모두 넣습니까?
- 개발자는 SQL 편집기 (SSMS, SQL Developer 등)와 소스 코드간에 쿼리를 어떻게 효율적으로 앞뒤로 이동합니까? C #의
@
접두사가 이것을 쉽게 만들어 주지만 각 SQL 줄을 인용하고 줄 바꿈을 피하는 많은 코드를 보았습니다.
"SELECT col1, col2...colN"\
"FROM painfulExample"\
"WHERE maintainability IS NULL"\
"AND modification.effort > @necessary"\
- SQL을 주변 애플리케이션 코드와 정렬하는 데 사용되는 들여 쓰기 문자는 각 실행마다 네트워크를 통해 전송됩니다. 이것은 소규모 응용 프로그램에는 중요하지 않지만 소프트웨어 사용이 증가함에 따라 더해질 수 있습니다.
전체 ORM (Entity Framework 또는 Hibernate와 같은 객체 관계형 매퍼)은 응용 프로그램 코드에서 임의로 페퍼 SQL을 제거 할 수 있습니다. SQL과 리소스 파일을 사용하는 것은 단지 예일뿐입니다. ORM, 헬퍼 클래스 등은 모두보다 깨끗한 코드의 목표를 달성하는 데 도움이 될 수 있습니다.
이전 답변에서 Kevin이 말했듯이 작은 프로젝트에서는 코드의 SQL을 사용할 수 있지만 큰 프로젝트는 작은 프로젝트로 시작하며 대부분의 팀이 되돌아 갈 수있는 가능성은 종종 코드 크기에 반비례합니다.
프로젝트에서 SQL을 유지하는 간단한 방법이 많이 있습니다. 내가 자주 사용하는 방법 중 하나는 각 SQL 문을 Visual Studio 리소스 파일 (일반적으로 "sql")에 넣는 것입니다. 도구에 따라 텍스트 파일, JSON 문서 또는 기타 데이터 소스가 합리적 일 수 있습니다. 경우에 따라 SQL 문자열을 적용하기위한 별도의 클래스가 최선의 선택 일 수 있지만 위에서 설명한 일부 문제가있을 수 있습니다.
SQL 예 : 어느 것이 더 우아해 보이는가? :
using(DbConnection connection = Database.SystemConnection()) {
var eyesoreSql = @"
SELECT
Viewable.ViewId,
Viewable.HelpText,
PageSize.Width,
PageSize.Height,
Layout.CSSClass,
PaginationType.GroupingText
FROM Viewable
LEFT JOIN PageSize
ON PageSize.Id = Viewable.PageSizeId
LEFT JOIN Layout
ON Layout.Id = Viewable.LayoutId
LEFT JOIN Theme
ON Theme.Id = Viewable.ThemeId
LEFT JOIN PaginationType
ON PaginationType.Id = Viewable.PaginationTypeId
LEFT JOIN PaginationMenu
ON PaginationMenu.Id = Viewable.PaginationMenuId
WHERE Viewable.Id = @Id
";
var results = connection.Query<int>(eyesoreSql, new { Id });
}
된다
using(DbConnection connection = Database.SystemConnection()) {
var results = connection.Query<int>(sql.GetViewable, new { Id });
}
SQL은 항상 쉽게 찾을 수있는 파일 또는 그룹화 된 파일 세트에 있으며, 각각 파일의 사용법보다는 설명이 포함 된 설명 이름을 가지고 있으며 각각은 애플리케이션 코드의 흐름을 방해하지 않는 주석을위한 공간이 있습니다. :
이 간단한 방법은 독방 쿼리를 실행합니다. 내 경험상, "외국어"의 사용이 더욱 정교 해짐에 따라 혜택이 확대됩니다.
리소스 파일을 사용하는 것은 단지 예일뿐입니다. 언어 (이 경우 SQL) 및 플랫폼에 따라 다른 방법이 더 적절할 수 있습니다.
이 방법과 다른 방법은 다음과 같은 방식으로 위 목록을 해결합니다.
- 데이터베이스 코드는 이미 중앙 집중식이기 때문에 쉽게 찾을 수 있습니다. 더 큰 프로젝트에서는 like-SQL을 별도의 파일 (예 :) 폴더 아래에 별도의 파일로 그룹화하십시오
SQL
.
- 두 번째, 세 번째 등의 데이터베이스 지원이 더 쉽습니다. 각 데이터베이스의 고유 한 명령문을 리턴하는 인터페이스 (또는 다른 언어 추상화)를 작성하십시오. 각 데이터베이스에 대한
return SqlResource.DoTheThing;
구현은 다음 과 유사한 명령문에 지나지 않습니다. 사실, 이러한 구현은 리소스를 건너 뛰고 문자열에 SQL을 포함 할 수 있지만 위의 일부 (전부는 아님) 문제가 여전히 발생합니다.
- 리팩토링은 간단합니다. 동일한 리소스를 재사용하십시오. 몇 가지 형식 문을 사용하여 다른 DBMS 시스템에 대해 동일한 리소스 항목을 오랫동안 사용할 수도 있습니다. 나는 이것을 자주한다.
- 2 차 언어를 사용하면 예를 들어 더 난해한 것이 아닌 설명적인 이름을 사용할 수 있습니다.
sql.GetOrdersForAccount
SELECT ... FROM ... WHERE...
- SQL 문은 크기와 복잡성에 관계없이 한 줄로 소환됩니다.
- SSMS 및 SQL Developer와 같은 데이터베이스 도구간에 수정이나 신중한 복사없이 SQL을 복사하여 붙여 넣을 수 있습니다. 따옴표가 없습니다. 후행 백 슬래시가 없습니다. 특히 Visual Studio 리소스 편집기의 경우 한 번의 클릭으로 SQL 문이 강조 표시됩니다. Ctrl + C를 누른 다음 SQL 편집기에 붙여 넣습니다.
리소스에서 SQL을 생성하는 것이 빠르므로 리소스 사용을 코드 내 SQL과 혼합 할 수있는 자극이 거의 없습니다.
선택한 방법에 관계없이 언어를 혼합하면 일반적으로 코드 품질이 저하됩니다. 여기에 설명 된 일부 문제와 솔루션이 개발자가 적절한 경우이 코드 냄새를 제거하는 데 도움이되기를 바랍니다.