Micro ORM을 사용하면서 인라인 SQL이 여전히 나쁜 습관으로 분류됩니까?


26

이것은 약간의 개방형 질문이지만 인라인 SQL 스크립트가 표준 인 세계에서 자랐기 때문에 의견이 필요했습니다. 그런 다음 우리는 SQL 주입 기반 문제를 잘 알고 있었고 SQL이 얼마나 취약한 지 모든 곳에서 문자열 조작.

그런 다음 ORM에 대한 쿼리를 설명하고 자체 SQL을 생성하게하는 ORM이 시작되었습니다. 많은 경우에 최적이 아니지만 안전하고 쉬웠습니다. ORM 또는 데이터베이스 추상화 계층의 또 다른 좋은 점은 SQL이 데이터베이스 엔진을 염두에두고 생성 되었기 때문에 MSSQL, MYSQL과 함께 Hibernate / Nhibernate를 사용할 수 있으며 코드는 구성 세부 사항 만 변경하지 않았다는 것입니다.

현재 마이크로 ORM이 더 많은 개발자를이기는 것처럼 보이는 현재의 날로 빨리 나아가서 전체 인라인 SQL 주제에 대해 왜 U-Turn을 사용했는지 궁금했습니다.

나는 ORM 구성 파일이 없다는 아이디어를 좋아하고 쿼리를보다 최적의 방식으로 작성할 수 있지만 SQL 주입과 같은 오래된 취약점에 자신을 다시 열어 놓은 것처럼 느낍니다. 하나의 데이터베이스 엔진이므로 소프트웨어가 여러 데이터베이스 엔진을 지원하기를 원하면 더 많은 문자열 해커를 수행해야하며 코드를 읽을 수없고 취약하게 만듭니다. (누군가가 언급하기 전에 대부분의 경우 SQL 주입으로부터 보호하는 대부분의 마이크로 orm에서 매개 변수 기반 인수를 사용할 수 있음을 알고 있습니다)

이런 종류의 사람들에 대한 사람들의 의견은 무엇입니까? 이 시나리오에서는 Dapper를 Micro ORM으로 사용하고이 시나리오에서는 NHibernate를 일반 ORM으로 사용하지만 각 필드의 대부분은 매우 유사합니다.

같은 내가 기간 인라인 SQL소스 코드 내의 SQL 문자열입니다. 소스 코드에서 SQL 문자열에 대한 디자인 논쟁은 논리의 근본적인 의도에서 벗어나기 때문에 예전에는 정적으로 입력 된 linq 스타일 쿼리가 여전히 1 개의 언어로 인기를 얻었지만 C #과 Sql을 한 페이지에서 이제 원시 소스 코드에 2 개의 언어가 섞여 있습니다. 명확히하기 위해 SQL 주입은 SQL 문자열 사용과 관련된 알려진 문제 중 하나입니다. 이미 매개 변수 기반 쿼리에서 발생하는 것을 막을 수 있다고 언급했지만 SQL 쿼리가 소스 코드에 뿌리 내리는 것과 같은 다른 문제를 강조합니다. DB 벤더 추상화가 부족하고 문자열 기반 쿼리에서 캡처 시간 수준의 오류를 잃어 버릴 수 있습니다. 이러한 문제는 우리가 높은 수준의 쿼리 기능을 사용하여 ORM의 시작과 함께 단계적으로 처리 한 모든 문제입니다.

따라서 강조 표시된 개별 문제에 중점을 두지 않았으며 대부분의 Micro ORM이이 메커니즘을 사용함에 따라 소스 코드에 SQL 문자열을 직접 입력하는 것이 더 수용 가능해졌습니다.

다음은 몇 가지 다른 관점을 가진 비슷한 질문입니다. 마이크로 orm 컨텍스트가없는 인라인 SQL에 대한 자세한 내용입니다.

https://stackoverflow.com/questions/5303746/is-inline-sql-hard-coding


1
의견을 묻지 않는 방식으로 질문을 다시 표현할 수 있다고 생각하십니까? 의견 수렴은 스택 교환의 Q & A 형식에 적합하지 않습니다.

"Micro ORM"쿼리는 언제든지 별도의 클래스로 추상화 할 수 있으며, 필요한 경우 DBMS를 변경할 때 실행중인 쿼리를 바꿀 수 있습니다.
CodeCaster

"Micro ORM"이라는 용어를 듣지 못했습니다. SQL을 완전히 인수하지 않는 ORM을 의미합니까, 아니면 다른 것이 있습니까?
Javier

조금 인터넷 검색을 한 후에는 .net으로 보입니다.
Javier

1
@GrandmasterB : 답을 찾는 이유를 설명하십시오. 나는 그것이 그 문제가 트레이드 오프의 문제라고 믿기 때문에 내 대답에서 그 문제를 거의 회피했습니다.
Robert Harvey

답변:


31

"인라인 SQL"로 설명하는 것을 실제로는 "매개 변수없이 문자열 연결"이라고해야하며 Micro ORM을 안전하게 사용하기 위해 그렇게하지 않아도됩니다.

이 Dapper 예제를 고려하십시오.

string sql = "SELECT * from user_profile WHERE FirstName LIKE @name;";
var result = connection.Query<Profile>(sql, new {name = "%"+name+"%"});

문자열 연결이 발생하더라도 완전히 매개 변수화됩니다. @ 기호를 보시겠습니까?

또는이 예 :

var dog = connection.Query<Dog>("select Age = @Age, Id = @Id", 
          new { Age = (int?)null, Id = guid });

다음 ADO.NET 코드와 거의 같습니다.

List<Dog> dog = new List<Dog>();
using(var cmd = connection.CreateCommand()) {
    cmd.CommandText = "select Age = @Age, Id = @Id";
    cmd.Parameters.AddWithValue("Age", DBNull.Value);
    cmd.Parameters.AddWithValue("Id", guid);
    using(var reader = cmd.ExecuteReader()) {
        while(reader.Read()) {
            int age = reader.ReadInt32("Age");
            int id = reader.ReadInt32("Id");
            dog.Add(new Dog { Age = age, Id = id });
        }
    }
}

이보다 유연성이 더 필요한 경우 Dapper는 SQL 템플릿과 AddDynamicParms()기능을 제공 합니다. 모든 SQL 인젝션 안전.

그렇다면 왜 먼저 SQL 문자열을 사용합니까?

같은 이유로 다른 ORM에서 사용자 지정 SQL을 사용합니다. ORM이 코드 생성 하위 최적화 SQL 일 수 있으므로 최적화해야합니다. 아마도 UNION과 같이 ORM에서 수행하기 어려운 작업을 원할 수도 있습니다. 또는 모든 프록시 클래스를 생성하는 복잡성을 피하고 싶을 수도 있습니다.

Dapper의 모든 CRUD 메소드에 대해 SQL 문자열을 작성하지 않으려는 경우 (누군가?)이 라이브러리를 사용할 수 있습니다.

https://github.com/ericdc1/Dapper.SimpleCRUD/

이렇게하면 손으로 작성한 SQL 문의 유연성을 제공하면서도 매우 간단하고 간단한 CRUD를 얻을 수 있습니다. 위의 ADO.NET 예제는 ORM이 등장하기 전에 모든 사람들이 수행 한 방식이었습니다. Dapper는 그보다 얇은 베니어입니다.


좋은 예, 나는 이미 큰 질문의 한 부분이기 때문에 매개 변수를 통해 SQL 주입을 회피 할 수 있다고 이미 언급했습니다 . 인라인 sql 이라는 용어를 사용할 때 의미가 무엇인지 설명하는 편집 내용이 추가되었습니다 .
Grofit

내 답변에 세부 사항을 추가했습니다.
Robert Harvey

2
SimpleCRUD에 대한 정보는 +1이 존재하는지 몰랐습니다.
Grofit

Java에서는 Hibernate 또는 EclipseLink보다 더 Mybatis 를 찾을 수 있습니다. 코드로 하드 ​​코딩하는 대신 XML로 미리 정의 된 문장을 사용하는 것이 좋습니다. 또한 최종 SQL을 향상시키기위한 전제 조건으로 흥미로운 기능을 추가합니다. 우리는 최근에 상당히 높은 동시성 및 복잡한 비즈니스가 아닌 API 웹에 사용했으며 훌륭하게 작동했습니다.
Laiv

2

나는 sql을 좋아 하고 문자열 리터럴에서 잘린 것을 볼 수 없었기 때문에 C # 프로젝트에서 실제 SQL 파일로 작업 할 수 있도록 약간의 VS 확장을 썼습니다. 자체 파일에서 sql을 편집하면 열 및 테이블, 구문 유효성 검사, 테스트 실행, 실행 계획 및 나머지에 대한 정보가 제공됩니다. 파일을 저장할 때 내 확장은 c # 래퍼 클래스를 생성하므로 연결 코드, 명령 코드 또는 매개 변수 또는 판독기 코드를 작성하지 마십시오. 다른 방법이 없기 때문에 쿼리가 모두 매개 변수화되며 입력 매개 변수 및 결과에 대한 정보와 함께 단위 테스트를 위해 리포지토리 및 POCO를 생성했습니다.

그리고 나는 무료 스테이크 나이프를 던졌습니다. 그녀가 돌아가서 DB를 정리하고 일부 열을 삭제하면 누락 된 열에 대한 참조가 C #의 컴파일 오류로 바로 뛰어납니다. 데이터베이스는 해킹 할 수있는 솔루션의 다른 프로젝트와 마찬가지로 코드에서 인터페이스를 찾을 수 있습니다. 솔루션이 컴파일되면 모든 쿼리가 작동하는 것입니다. 유효하지 않은 캐스트 또는 유효하지 않은 열 이름 또는 유효하지 않은 쿼리로 인한 런타임 오류가 없습니다.

우리가 여전히 직장에서 사용하고있는 dapper를 되돌아 보면 2016 년에 이것이 데이터 액세스에서 가장 멋진 것임을 믿을 수 없습니다. 런타임 msil 생성은 영리하지만 모든 오류는 런타임 오류이며 다른 목적을위한 문자열 조작과 같은 문자열 조작은 시간이 많이 걸리고 취약하며 오류가 발생하기 쉽습니다. 그리고 POCO에서 열 이름을 반복해서 작성하고 수작업으로 작성하고 유지해야하는 방법은 무엇입니까?

그래서 당신은 간다. 여가 시간에 어린 아이들과 많은 취미를 겪고있는 전례가없는 개발자의 완벽한 데이터 액세스 기술을보고 싶다면 여기에 있습니다 .


당신은 작은 "혁신"을 많이 생각하는 것 같지만, 이것이 Entity Framework의 ExecuteStoreQuery 또는 ExecuteStoreCommand 와 다른 점은 무엇입니까?
Robert Harvey

EF 또는 SQL 토론에 참여하지 않습니다. 내 일은 SQL을 사용하려는 사람들을위한 것입니다. 따라서 SQL을 실행하는 방법으로 ExecuteStoreQuery ()가 POCO를 채울 것이지만 여전히 POCO를 정의해야합니까? 또한 SQL을 파일에 넣거나 매개 변수를 만드는 데 도움이되지 않습니다. 코드에서 쿼리를 검색하거나 테스트 할 수 없습니다. 열을 삭제해도 응용 프로그램에서 컴파일 오류가 발생하지 않습니다. 나는 계속할 수는 있지만, 나는 나 자신을 반복하고 있다는 것을 두려워한다. 프랑스어로 소리를 줄이십시오! 영어가 온다.
bbsimonbb

EF는 모든 POCO를 자동으로 생성 할 수 있습니다. 내가 여기서 무엇을 놓치고 있습니까? Dapper와 Massive의 진정한 혁신은 POCO가 전혀 필요하지 않다는 것입니다. 당신은 그냥 사용할 수 있습니다 dynamic.
Robert Harvey

나는 EF에 대해 거의 아무것도 모른다. ExecuteStoreQuery ()는 엔티티를 채 웁니다. 쿼리에서 엔터티 생성 합니까 ? 엔터티는 쿼리가 아닌 DB 객체에서 (또는 그 반대로) 생성됩니다. 쿼리가 기존 엔티티와 일치하지 않으면 POCO를 작성해야합니다.
bbsimonbb

1
:-)는 내가 최선의 아이디어를 자유롭게 내놓을 때 광고비에 민감하다고 말해야합니다. 다음은 최근의 공격적인 상업주의입니다. 3 분이 지났을 때, 내가 뭔가를하고 있는지 아닌지 알아야합니다.
bbsimonbb

1

리포지토리 디자인 패턴뿐만 아니라 매개 변수화 된 쿼리를 통해 주입 공격을 방지하기 위해 쿼리에 들어가는 내용을 완벽하게 제어 할 수 있습니다. 이 경우 인라인 SQL은 크고 복잡한 쿼리에 대한 가독성 이외의 문제가 아니며 저장 프로 시저에 있어야합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.