다음을 통해 공유


원시 SQL 쿼리(EF6)

Entity Framework를 사용하면 엔터티 클래스와 함께 LINQ를 사용하여 쿼리할 수 있습니다. 그러나 데이터베이스에 대해 직접 원시 SQL을 사용하여 쿼리를 실행하려는 경우가 생길 수 있습니다. 여기에는 현재 저장 프로시저에 대한 매핑을 지원하지 않는 Code First 모델에 유용할 수 있는 저장 프로시저 호출이 포함됩니다. 이 토픽에서 설명하는 방법은 Code First 및 EF 디자이너를 사용하여 만든 모델에 동일하게 적용됩니다.

엔터티에 대한 SQL 쿼리 작성

DbSet의 SqlQuery 메서드를 사용하면 엔터티 인스턴스를 반환하는 원시 SQL 쿼리를 작성할 수 있습니다. 반환된 개체는 LINQ 쿼리에서 반환된 경우와 마찬가지로 컨텍스트로 추적됩니다. 예시:

using (var context = new BloggingContext())
{
    var blogs = context.Blogs.SqlQuery("SELECT * FROM dbo.Blogs").ToList();
}

LINQ 쿼리와 마찬가지로 이 쿼리는 결과가 열거될 때까지 실행되지 않습니다. 위의 예제에서는 ToList를 호출하여 수행됩니다.

두 가지 이유로 원시 SQL 쿼리를 작성할 때마다 주의해야 합니다. 첫째, 실제 요청된 형식의 엔터티만 반환하도록 쿼리를 작성해야 합니다. 예를 들어 상속과 같은 기능을 사용하는 경우 잘못된 CLR 형식의 엔터티를 만드는 쿼리를 작성하기 쉽습니다.

둘째, 일부 형식의 원시 SQL 쿼리는 특히 SQL 삽입 공격과 관련된 잠재적인 보안 위험을 노출합니다. 이러한 공격을 방어하려면 쿼리에서 매개 변수를 올바른 방법으로 사용해야 합니다.

저장 프로시저에서 엔터티 로드

DbSet.SqlQuery를 사용하여 저장 프로시저의 결과에서 엔터티를 로드할 수 있습니다. 예를 들어 다음 코드는 데이터베이스에서 dbo.GetBlogs 프로시저를 호출합니다.

using (var context = new BloggingContext())
{
    var blogs = context.Blogs.SqlQuery("dbo.GetBlogs").ToList();
}

다음 구문을 사용하여 저장 프로시저에 매개 변수를 전달할 수도 있습니다.

using (var context = new BloggingContext())
{
    var blogId = 1;

    var blogs = context.Blogs.SqlQuery("dbo.GetBlogById @p0", blogId).Single();
}

엔터티 이외 형식의 SQL 쿼리 작성

기본 형식을 비롯한 모든 형식의 인스턴스를 반환하는 SQL 쿼리는 Database 클래스의 SqlQuery 메서드를 사용하여 만들 수 있습니다. 예시:

using (var context = new BloggingContext())
{
    var blogNames = context.Database.SqlQuery<string>(
                       "SELECT Name FROM dbo.Blogs").ToList();
}

개체가 엔터티 형식의 인스턴스인 경우에도 데이터베이스의 SqlQuery에서 반환된 결과는 컨텍스트로 추적되지 않습니다.

데이터베이스에 원시 명령 보내기

쿼리가 아닌 명령은 Database에서 ExecuteSqlCommand 메서드를 사용하여 데이터베이스로 보낼 수 있습니다. 예시:

using (var context = new BloggingContext())
{
    context.Database.ExecuteSqlCommand(
        "UPDATE dbo.Blogs SET Name = 'Another Name' WHERE BlogId = 1");
}

ExecuteSqlCommand를 사용하여 데이터베이스의 데이터를 변경한 항목은 엔터티가 데이터베이스에서 로드되거나 다시 로드될 때까지 내용을 파악하기 힘듭니다.

출력 매개 변수

출력 매개 변수를 사용하는 경우 결과를 완전히 읽을 때까지 해당 값을 사용할 수 없습니다. 이는 DbDataReader의 기본 동작 때문입니다. 자세한 내용은 DataReader를 사용한 데이터 검색을 참조하세요.