.NET으로 SQL Server 사용

본 .NET Bookshelf 가이드는 샘플 앱에서영구 데이터를 Compute Engine VM에서 실행 중인 Microsoft SQL Server에 저장하는 방법을 보여줍니다.

이 페이지는 여러 페이지로 구성된 가이드의 일부입니다. 가이드 처음으로 돌아가서 설정 안내를 보려면 .NET Bookshelf 앱으로 이동하세요.

SQL Server 인스턴스 만들기

  1. 새 Compute Engine 인스턴스를 만듭니다.

    VM 인스턴스 페이지로 이동

  2. 인스턴스 IDlibrary를 입력합니다.

  3. 영역으로 us-west1-a를 선택합니다.

  4. 부팅 디스크 섹션에서 변경을 클릭합니다.

  5. 애플리케이션 이미지 탭에서 Windows Server 2012 R2의 SQL Server 2014 Standard 이미지를 선택한 후 선택을 클릭합니다.

  6. 만들기를 클릭해 VM 인스턴스를 만듭니다.

  7. 준비가 되면 인스턴스의 이름을 클릭합니다. 인스턴스가 준비되는 데 몇 분 정도 걸릴 수 있습니다. 인스턴스가 준비되면 인스턴스 목록에 표시됩니다.

  8. 인스턴스 세부정보 페이지에서 Windows 비밀번호 설정을 클릭합니다.

  9. 원하는 사용자 이름을 입력하고 설정을 클릭해 인스턴스의 사용자 계정을 만듭니다. 제공된 비밀번호를 기록해 두고 대화상자를 닫습니다.

SQL Server 데이터베이스 만들기

  1. VM 인스턴스 목록에서 SQL Server 인스턴스 옆에 있는 RDP 링크를 클릭합니다. 인스턴스를 만드는 과정에서 설정한 사용자 이름과 비밀번호로 로그인합니다.

  2. Windows 시작 메뉴에서 SQL Server 2014 Manage를 입력합니다.

  3. SQL Server 2014 Management Studio를 마우스 오른쪽 버튼으로 클릭하고 Run as administrator(관리자 권한으로 실행)를 선택합니다.

  4. Connect to Server(서버에 연결) 창에서 Connect(연결)를 클릭합니다.

  5. Databases(데이터베이스)를 마우스 오른쪽 버튼으로 클릭하고 New database(새 데이터베이스)를 선택합니다.

  6. 데이터베이스 이름을 bookshelf로 지정한 후 OK(확인)를 클릭합니다.

SQL Server 구성

  1. SQL Server 2014 Management Studio에서 library SQL Server 인스턴스의 Security(보안) 폴더를 클릭합니다.

  2. Logins(로그인)를 마우스 오른쪽 버튼으로 클릭하고 New login(새 로그인)을 선택합니다.

  3. Login name(로그인 이름)dotnetapp을 입력합니다.

  4. Authentication(인증) 방법으로 SQL Server Authentication(SQL Server 인증)을 클릭합니다.

  5. Password(암호)에 원하는 비밀번호를 입력합니다. Enforce password policy(암호 정책 강제 적용) 옵션을 사용 설정하면 안 됩니다.

  6. Default Database(기본 데이터베이스)를 이전에 만든 bookshelf 데이터베이스로 변경합니다.

  7. New login(새 로그인) 대화상자의 왼쪽에서 User Mapping(사용자 매핑)을 클릭하고 다음 단계를 완료합니다.

    1. bookshelf 데이터베이스에 해당하는 Map(매핑) 체크박스를 클릭합니다.

    2. Database role membership for(데이터베이스 역할 멤버 자격): bookshelf에서 다음을 제외한 모든 역할을 클릭합니다.

      • db_denydatareader

      • db_denydatawriter

  8. OK(확인)를 클릭해 새 데이터베이스 로그인 계정을 만듭니다.

  9. 생성된 사용자가 SQL Server 인증을 사용하도록 설정되어 있으므로 SQL Server에서 이 인증 방법을 허용하도록 구성해야 합니다. SQL Server 2014 Management Studio에서 생성된 Library(라이브러리) SQL Server 인스턴스를 마우스 오른쪽 버튼으로 클릭하고 Properties(속성)를 선택합니다.

  10. Server Properties(서버 속성) 대화상자의 왼쪽 메뉴에서 Security(보안)를 클릭합니다.

  11. Server Authentication(서버 인증) 설정에서 SQL Server and Windows Authentication mode(SQL Server 및 Windows 인증 모드)를 선택한 후 OK(확인)를 클릭합니다.

  12. Library(라이브러리) SQL Server 인스턴스를 마우스 오른쪽 버튼으로 클릭하고 Restart(다시 시작)를 선택해 SQL Server 서비스를 다시 시작합니다.

SQL Server의 방화벽 규칙 만들기

다른 클라이언트가 인터넷을 통해 새로 만든 SQL Server 인스턴스에 연결할 수 있도록 포트 1433에서 트래픽을 허용하는 방화벽 규칙을 구성합니다.

  1. Google Cloud Platform Console에서 방화벽 규칙 섹션으로 이동합니다.

    방화벽 규칙 열기

  2. 방화벽 규칙 추가를 클릭하고 다음 필드를 작성합니다.

    1. 방화벽 규칙 이름allow-tcp-1433을 입력합니다.

    2. 소스 필터IP 범위를 선택합니다.

    3. 모든 IP 주소의 액세스를 허용하도록 소스 IP 범위0.0.0.0/0을 입력합니다.

    4. 허용되는 프로토콜 및 포트tcp:1433을 입력합니다.

  3. 만들기를 클릭해 방화벽 규칙을 만듭니다.

설정 구성

  1. getting-started-dotnet\aspnet\2-structured-data 디렉토리에서 2-structured-data.sln을 더블클릭해 Visual Studio에서 샘플 앱을 엽니다.

  2. Solution Explorer(솔루션 탐색기) 창에서 Web.config를 클릭합니다.

  3. Web.config에서 다음 단계를 완료합니다.

    1. GoogleCloudSamples:ProjectId를 프로젝트 ID로 설정합니다.

    2. GoogleCloudSamples:BookStoresqlserver로 설정합니다.

    3. 파일 하단 쪽에 있는 <connectionStrings>에서 name="LocalSqlServer" 속성이 포함된 connectionStrings XML 하위 요소를 찾습니다. connectionString 값을 SQL Server 인스턴스의 외부 IP 주소, 데이터베이스 이름, 사용자 이름, 비밀번호로 업데이트합니다. 예를 들어 원격 SQL Server의 connectionString을 IP 104.155.20.171database = bookshelf, user = dotnetapp, password = test로 업데이트하면 다음과 같습니다.

      connectionString="Data Source=104.155.20.171;Initial Catalog=bookshelf;Integrated Security=False;User ID=dotnetapp;Password=test;MultipleActiveResultSets=True"

  4. Web.config를 저장하고 닫습니다.

  5. Visual Studio 메뉴에서 Build(빌드)를 클릭한 후 Build Solution(솔루션 빌드)을 선택해 솔루션을 빌드합니다.

  6. 데이터베이스 테이블을 만들려면 Visual Studio 메뉴에서 Tools(도구) > Nuget Package Manager(Nuget 패키지 관리자) > Package Manager Console(패키지 관리자 콘솔)로 이동합니다. PM > 프롬프트에 다음 명령어를 입력합니다.

    Add-Migration Init
    
  7. Bookshelf 앱의 도서 데이터를 저장하는 데 사용되는 SQL Server 데이터베이스의 테이블을 만듭니다. Package Manager Console(패키지 관리자 콘솔)에서 다음 명령어를 입력합니다.

    Update-Database
    

로컬 머신에서 앱 실행

Visual Studio에서 F5 키를 눌러 프로젝트를 실행합니다. 이제 앱의 웹페이지를 찾아보고 도서를 추가, 편집, 삭제할 수 있습니다.

앱 구조

이 다이어그램은 앱의 구성요소가 어떻게 연결되는지 보여줍니다. 이 앱은 기본 ASP.NET MVC 패턴과 유사합니다. IBookStore 인터페이스는 BooksControllerDbBookStore 사이에 위치하므로 코드 변경 없이 도서 데이터를 Cloud Datastore에 저장하도록 전환할 수 있습니다.

Bookshelf 앱 구조

코드 이해하기

이 섹션에서는 앱 코드에 대해 단계별로 알아보고 이 코드의 작동 방식을 설명합니다.

데이터 모델

Book 클래스에는 도서 하나에 대한 정보와 이후 가이드에서 사용되는 추가 필드가 포함되어 있습니다.

    [Bind(Include = "Title, Author, PublishedDate, Description")]
    public class Book
    {
        [Key]
        public long Id { get; set; }

        [Required]
        public string Title { get; set; }

        public string Author { get; set; }

        [Display(Name = "Date Published")]
        [DataType(DataType.Date)]
        public DateTime? PublishedDate { get; set; }

        public string ImageUrl { get; set; }

        [DataType(DataType.MultilineText)]
        public string Description { get; set; }

        public string CreatedById { get; set; }
    }

Entity Framework의 DbSet에서 LINQ 쿼리 및 Create, Read, Update, Delete(CRUD) 작업을 SQL 쿼리로 변환합니다. ApplicationDbContext 클래스에 도서의 DbSet가 보관됩니다.

public class ApplicationDbContext : DbContext
{
    // ...
    public DbSet<Book> Books { get; set; }

제출 수정이 가능한 양식

추가/수정 HTML 양식을 사용하면 도서 제출을 추가하고 수정할 수 있습니다.

추가/수정 양식 이미지

이 HTML 양식은 Razor 템플릿을 사용하여 만듭니다. Razor 템플릿은 양식에 제목, 저자, 게시 날짜, 설명에 대한 텍스트 입력 필드가 포함되도록 지정합니다.

<form action="/Books/@Model.FormAction/@Model.Book.Id" method="post" id="book-form" enctype="multipart/form-data">
    @Html.AntiForgeryToken()
    <div class="form-group">
        @Html.LabelFor(model => model.Book.Title)
        @Html.EditorFor(model => model.Book.Title, new { htmlAttributes = new { @class = "form-control" } })
        @Html.ValidationMessageFor(model => model.Book.Title, "", new { @class = "text-danger" })
    </div>

    <div class="form-group">
        @Html.LabelFor(model => model.Book.Author)
        @Html.EditorFor(model => model.Book.Author, new { htmlAttributes = new { @class = "form-control" } })
        @Html.ValidationMessageFor(model => model.Book.Author, "", new { @class = "text-danger" })
    </div>

    <div class="form-group">
        @Html.LabelFor(model => model.Book.PublishedDate)
        @Html.EditorFor(model => model.Book.PublishedDate, new { htmlAttributes = new { @class = "form-control", @type = "text" } })
        @Html.ValidationMessageFor(model => model.Book.PublishedDate, "", new { @class = "text-danger" })
    </div>

    <div class="form-group">
        @Html.LabelFor(model => model.Book.Description)
        @Html.EditorFor(model => model.Book.Description, new { htmlAttributes = new { @class = "form-control", @type = "text" } })
        @Html.ValidationMessageFor(model => model.Book.Description, "", new { @class = "text-danger" })
    </div>

    <button type="submit" class="btn btn-success">Save</button>
</form>

양식 제출 처리

Add Book(도서 추가)을 클릭하면 BooksController.Create() 메소드에서 이 양식을 표시합니다. 양식을 작성하고 Save(저장)를 클릭하면 BooksController.Create() 메소드에서 양식 콘텐츠를 받은 후 IBookStore::Create() 메소드를 통해 SQL Server 데이터베이스로 이 콘텐츠를 전송합니다. Create 메소드는 HttpPost로 주석 처리됩니다.

        // GET: Books/Create
        public ActionResult Create()
        {
            return ViewForm("Create", "Create");
        }

        // POST: Books/Create
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Create(Book book)
        {
            if (ModelState.IsValid)
            {
                _store.Create(book);
                return RedirectToAction("Details", new { id = book.Id });
            }
            return ViewForm("Create", "Create", book);
        }

DbBookStore 클래스는 SQL Server 데이터베이스에 저장된 데이터의 쿼리 및 CRUD 작업을 수행하도록 ApplicationDbContext 클래스를 호출합니다. SQL 쿼리는 Entity Framework라는 객체 관계형 매퍼(ORM)를 사용하여 작성됩니다. 객체 관계형 매퍼를 사용하면 데이터 모델을 간단한 C# 클래스로 작성해 모든 SQL을 자동으로 생성할 수 있습니다.

Create()와 같은 DbBookStore의 CRUD 메소드는 ApplicationDbContext 클래스에 대한 간단한 호출입니다.

public void Create(Book book)
{
    var trackBook = _dbcontext.Books.Add(book);
    _dbcontext.SaveChanges();
    book.Id = trackBook.Id;
}

도서 나열

도서를 추가한 후 Books(도서) 링크를 클릭해 /Books 페이지로 이동하면 현재 SQL Server 데이터베이스에 저장된 모든 도서가 나와 있습니다. List() 메소드가 데이터베이스에서 검색한 데이터를 사용하여 모든 도서를 나열하는 작업을 수행합니다.

public BookList List(int pageSize, string nextPageToken)
{
    IQueryable<Book> query = _dbcontext.Books.OrderBy(book => book.Id);
    if (nextPageToken != null)
    {
        long previousBookId = long.Parse(nextPageToken);
        query = query.Where(book => book.Id > previousBookId);
    }
    var books = query.Take(pageSize).ToArray();
    return new BookList()
    {
        Books = books,
        NextPageToken = books.Count() == pageSize ? books.Last().Id.ToString() : null
    };
}

List() 메소드는 도서의 DbSet에서 도서를 읽는 LINQ 쿼리를 작성합니다. 이 쿼리의 페이징 구현 방식은 약간 복잡합니다. 쿼리가 10개의 도서를 읽은 후 마지막 도서의 IdNextPageToken에 저장합니다. More(더보기) 버튼을 클릭하면 List() 메소드에서 nextPageToken을 압축해제해 마지막 도서의 Id를 가져온 후 ID 값이 더 큰 도서를 쿼리합니다.