연습: 형식 공급자를 사용하여 SQL 데이터베이스에 액세스(F#)

이 연습에서는 F# 3.0에서 사용할 수 있는 SqlDataConnection(LINQ to SQL) 형식 공급자를 사용하여 데이터베이스에 대한 라이브 연결 시 SQL 데이터베이스에서 데이터 형식을 생성하는 방법에 대해 설명합니다.데이터베이스에 대한 라이브 연결이 없지만 LINQ to SQL 스키마 파일(DBML 파일)이 있는 경우 연습: DBML 파일에서 F# 형식 생성(F#)를 참조하십시오.

이 연습에서는 다음 작업을 수행합니다.이 연습을 완료하려면 이 순서대로 수행해야 합니다.

  • Preparing a test database

  • Creating the project

  • Setting up a type provider

  • Querying the data

  • Working with nullable fields

  • Calling a stored procedure

  • Updating the database

  • Executing Transact-SQL code

  • Using the full data context

  • Deleting data

  • Create a test database (as needed)

테스트 데이터베이스를 준비하고 있습니다.

SQL Server에서 실행 중인 서버에서 테스트 목적으로 데이터베이스를 만듭니다.이 작업을 수행하려면 섹션 MyDatabase Create Script에서 이 페이지 하단의 데이터베이스 작성 스크립트를 사용할 수 있습니다.

테스트 데이터베이스를 준비하는 방법

  • MyDatabase Create Script를 실행하려면 보기 메뉴를 열고 SLQ Server 개체 탐색기를 선택하거나 Ctrl+\, Ctrl+S 키를 선택합니다.SQL Server 개체 탐색기 창에서 해당 인스턴스의 바로 가기 메뉴를 열고 새 쿼리를 선택하고 이 페이지 아래쪽에 스크립트를 복사한 다음 스크립트를 편집기로 붙여 넣습니다.SQL 스크립트를 실행하려면 도구 모음 아이콘을 삼각형 기호와 함께 선택하거나 Ctrl+Q 키를 선택합니다.SQL Server 개체 탐색기에 대한 자세한 내용은 연결된 데이터베이스 개발을 참조하십시오.

프로젝트 만들기

그 다음 F# 응용 프로그램 프로젝트를 만듭니다.

프로젝트를 만들고 설정하려면

  1. 새로운 F# 응용 프로그램 프로젝트를 만듭니다.

  2. .FSharp.Data.TypeProviders, System.DataSystem.Data.Linq에 대한 참조를 추가합니다.

  3. F# 코드 파일 Program.fs 상단에 다음 코드 줄을 추가하여 적절한 네임스페이스를 엽니다.

    open System
    open System.Data
    open System.Data.Linq
    open Microsoft.FSharp.Data.TypeProviders
    open Microsoft.FSharp.Linq
    
  4. 대부분의 F# 프로그램과 마찬가지로 이 연습에서 컴파일된 프로그램으로 코드를 실행하거나 스크립트로 대화형으로 실행할 수 있습니다.스크립트를 사용하고 싶은 경우 프로젝트 노드의 바로 가기 메뉴를 열고 새 항목 추가를 선택하고 F# 스크립트 파일을 추가하고 각 단계의 코드를 스크립트에 추가합니다.파일 상단에 다음 줄을 추가하여 어셈블리 참조를 로드해야 합니다.

    #r "System.Data.dll"
    #r "FSharp.Data.TypeProviders.dll"
    #r "System.Data.Linq.dll"
    

    그런 다음 추가할 때 코드의 각 블록을 선택하고 Alt+Enter를 눌러 F# Interactive에서 실행할 수 있습니다.

형식 공급자 설정

이 단계에서는 데이터베이스 스키마에 대한 형식 공급자를 만듭니다.

직접 데이터베이스 연결에서 형식 공급자를 설정하는 방법

  • 형식 공급자를 사용하여 SQL 데이터베이스를 쿼리하는 데 사용할 수 있는 형식을 만드는 데 필요한 중요한 코드 줄 둘이 있습니다.먼저, 형식 공급자를 인스턴스화합니다.이렇게 하려면 정적 제네릭 매개 변수를 사용하여 SqlDataConnection에 대한 형식 약어가 표시되는 모양을 만듭니다.SqlDataConnection는 SQL 형식 공급자이며 ADO.NET 프로그래밍에 사용되는 SqlConnection 형식과 혼동해서는 안 됩니다.연결하려는 데이터베이스가 있고 연결 문자열이 있는 경우 다음 코드를 사용하여 형식 공급자를 호출합니다.주어진 예제 문자열 대신 사용자 지정 연결 문자열을 사용합니다.예를 들어, 서버가 MYSERVER이고 데이터베이스 인스턴스가 INSTANCE이며 데이터베이스 이름이 MyDatabase이고 Windows 인증을 사용하여 데이터베이스에 액세스하려는 경우 연결 문자열은 다음 예제 코드에 제공된 것과 같아집니다.

    type dbSchema = SqlDataConnection<"Data Source=MYSERVER\INSTANCE;Initial Catalog=MyDatabase;Integrated Security=SSPI;">
    let db = dbSchema.GetDataContext()
    
    // Enable the logging of database activity to the console.
    db.DataContext.Log <- System.Console.Out
    

    이제 데이터베이스 테이블을 나타내는 모든 생성된 형식이 포함된 부모 형식인 dbSchema 형식이 있습니다.db 개체토 있습니다. 이 개체는 데이터베이스에서 모든 테이블을 멤버로 가지고 있습니다.테이블 이름은 속성이며 이러한 속성의 형식은 F# 컴파일러에 의해 생성됩니다.형식 자체는 dbSchema.ServiceTypes 아래에 중첩 형식으로 나타냅니다.따라서 이러한 테이블의 행에 대해 검색되는 데이터는 해당 테이블에 대해 생성된 적절한 형식의 인스턴스입니다.해당 형식의 이름은 ServiceTypes.Table1입니다.

    F# 언어 쿼리를 SQL 쿼리로 해석하는 방법에 익숙해지도록 데이터 컨텍스트에 따라 Log 속성을 설정하는 줄을 검토합니다.

    형식 공급자가 만든 형식을 자세히 살펴보려면 다음 코드를 추가합니다.

    let table1 = db.Table1
    

    table1을 가리킨 후 형식을 확인합니다.해당 형식은 System.Data.Linq.Table<dbSchema.ServiceTypes.Table1>이며 제네릭 인수는 각 행의 형식이 생성된 형식인 dbSchema.ServiceTypes.Table1임을 의미합니다.데이터베이스의 각 테이블에 대한 비슷한 유형의 컴파일러를 만듭니다.

데이터를 쿼리하고 있습니다.

이 단계에서는 F# 쿼리 식을 사용하여 쿼리를 작성합니다.

데이터에 쿼리하는 방법

  1. 이제 해당 테이블에 대한 쿼리를 데이터베이스에서 만듭니다.다음 코드를 추가합니다.

    let query1 =
            query {
                for row in db.Table1 do
                select row
            }
    query1 |> Seq.iter (fun row -> printfn "%s %d" row.Name row.TestData1)
    

    단어 query의 모양은 일반 데이터베이스 쿼리와 비슷한 결과의 컬렉션을 생성하는 계산 식의 일종인 쿼리 식임을 나타냅니다.큐를 마우스로 가리키면 쿼리 계산 식을 정의하는 형식인 Linq.QueryBuilder 클래스(F#)의 인스턴스라고 표시됩니다.query1을 가리키면 해당 항목이 IQueryable<T> 인스턴스인지 확인할 수 있습니다.이름에서 알 수 있듯이 IQueryable<T>는 쿼리 결과가 아니라, 쿼리할 수 있는 데이터를 나타냅니다.쿼리는 지연 평가에 해당합니다. 즉 데이터베이스는 쿼리가 평가될 때만 쿼리됩니다.마지막 줄은 Seq.iter을 통해 쿼리를 전달합니다.열거할 수 있는 쿼리는 시퀀스와 마찬가지로 반복할 수 있습니다.자세한 내용은 쿼리 식(F#)을 참조하십시오.

  2. 이제 쿼리 연산자를 쿼리에 추가합니다.더 복잡한 쿼리를 생성하는 데 사용할 수 있는 사용 가능한 쿼리 연산자는 여러 개가 있습니다.또한 이 예제는 쿼리 변수를 제거하고 파이프라인 연산자를 대신 사용하는 내용을 보여줍니다.

    query {
            for row in db.Table1 do
            where (row.TestData1 > 2)
            select row
          }
    |> Seq.iter (fun row -> printfn "%d %s" row.TestData1 row.Name)
    
  3. 두 테이블을 조인하여 더 복잡한 쿼리를 추가합니다.

    query {
            for row1 in db.Table1 do
            join row2 in db.Table2 on (row1.Id = row2.Id)
            select (row1, row2)
    }
    |> Seq.iteri (fun index (row1, row2) ->
         if (index = 0) then printfn "Table1.Id TestData1 TestData2 Name Table2.Id TestData1 TestData2 Name"
         printfn "%d %d %f %s %d %d %f %s" row1.Id row1.TestData1 row1.TestData2 row1.Name
             row2.Id (row2.TestData1.GetValueOrDefault()) (row2.TestData2.GetValueOrDefault()) row2.Name)
    
  4. 실제 코드에서 쿼리 매개 변수는 일반적으로 컴파일 타임 상수가 아닌 값 또는 변수입니다.매개 변수를 사용하는 함수에서 쿼리를 래핑하는 다음 코드를 추가한 다음 값 10을 사용하여 해당 함수를 호출합니다.

    let findData param =
        query {
            for row in db.Table1 do
            where (row.TestData1 = param)
            select row
            }
    findData 10 |> Seq.iter (fun row -> printfn "Found row: %d %d %f %s" row.Id row.TestData1 row.TestData2 row.Name)
    

null을 허용하는 필드에서 작업

데이터베이스에서 필드에 종종 null 값을 사용할 수 있습니다..NET 형식 시스템에서는 가능한 형식으로 null을 갖지 못하기 때문에 null을 허용하는 데이터의 일반 숫자 데이터 형식을 사용할 수 없습니다.따라서 이러한 값은 Nullable<T> 형식의 인스턴스로 표현됩니다.이런 필드의 값에 필드 이름을 사용하여 직접 액세스하는 대신 일부 단계를 추가해야 합니다.Value 속성을 사용하여 ull을 허용하는 형식의 내부 값에 액세스할 수 있습니다.Value 속성은 개체가 값 대신 null을 사용할 경우 예외를 throw합니다.HasValue Boolean 메서드를 사용하여 값이 존재하는지 여부를 결정하거나 GetValueOrDefault를 사용하여 모든 경우에 실제 값을 가지는지 확인할 수 있습니다.GetValueOrDefault을 사용하고 데이터베이스에 null이 있는 경우 문자열 형식은 빈 문자열, 정수 형식은 0 또는 부동 소수점 형식은 0.0 같은 값으로 대체됩니다.

쿼리의 where 절에서 null을 허용하는 값에 대해 같음 테스트나 비교를 수행해야 하는 경우 Linq.NullableOperators 모듈(F#)에 있는 null을 허용하는 연산자를 사용할 수 있습니다.이는 일반 비교 연산자인 =, > 및 <=와 비슷하지만 null을 허용하는 값이 있는 왼쪽 또는 오른쪽에 있는 연산자에 물음표 표시가 된다는 점이 다릅니다.예를 들어, 연산자 >?는 오른쪽에 있는 nullable 값을 가진 연산자 보다 큽니다.이러한 연산자의 작동 방식은 식의 한쪽이 null인 경우 식은 false로 평가되는 것입니다.where 절에서 이는 일반적으로 null 필드를 포함하는 행이 선택되지 않았고 쿼리 결과를 반환하지 않은 것을 의미합니다.

Null을 허용하는 필드를 사용하여 작업하는 방법

  • 다음 코드는 null을 허용하는 값의 작업을 보여줍니다. TestData1는 null을 허용하는 정수 필드라고 가정합니다.

    query {
            for row in db.Table2 do
            where (row.TestData1.HasValue && row.TestData1.Value > 2)
            select row
          }
    |> Seq.iter (fun row -> printfn "%d %s" row.TestData1.Value row.Name)
    
    query {
            for row in db.Table2 do
            // Use a nullable operator ?>
            where (row.TestData1 ?> 2)
            select row
          }
    |> Seq.iter (fun row -> printfn "%d %s" (row.TestData1.GetValueOrDefault()) row.Name)
    

저장 프로시저 호출

데이터베이스에 저장된 모든 프로시저는 F#에서 호출할 수 있습니다.형식 공급자 인스턴스화에서 정적 매개 변수 StoredProcedures를 true로 설정해야 합니다.형식 공급자 SqlDataConnection에는 생성되는 형식을 구성하는 데 사용할 수 있는 여러 가지 정적 메서드가 포함됩니다.자세한 내용은 SqlDataConnection 형식 공급자(F#)을 참조하십시오.데이터 컨텍스트 형식의 메서드가 각 저장된 프로시저에 대해 생성됩니다.

저장된 프로시저를 호출하는 방법

  • 저장 프로시저가 null을 허용하는 매개 변수를 이용하는 경우 적절한 Nullable<T> 값을 전달해야 합니다.스칼라 또는 테이블을 반환하는 저장된 프로시저 메서드의 반환 값은 반환된 데이터에 액세스할 수 있는 속성이 포함된 ISingleResult<T>입니다.ISingleResult<T>에 대한 형식 인수는 특정 절차에 따라 다르며 형식 공급자가 생성하는 형식 중 하나이기도 합니다.Procedure1 이름의 저장 프로시저에서 형식은 Procedure1Result입니다.형식 Procedure1Result에는 반환된 테이블에 열 이름을 포함하며 스칼라 값을 반환하는 저장 프로시저의 경우 반환 값을 나타냅니다.

    다음 코드는 두 개의 null을 허용하는 정수를 매개 변수로 사용하고 TestData1이라는 열을 반환하는 쿼리를 실행하고 정수를 반환하는 데이터베이스에 절차 Procedure1가 있다고 가정합니다.

    
    
    type schema = SqlDataConnection<"Data Source=MYSERVER\INSTANCE;Initial Catalog=MyDatabase;Integrated Security=SSPI;",
                                    StoredProcedures = true>
    
    let testdb = schema.GetDataContext()
    
    let nullable value = new System.Nullable<_>(value)
    
    let callProcedure1 a b =
        let results = testdb.Procedure1(nullable a, nullable b)
        for result in results do
            printfn "%d" (result.TestData1.GetValueOrDefault())
        results.ReturnValue :?> int
    
    printfn "Return Value: %d" (callProcedure1 10 20)
    

데이터베이스 업데이트

LINQ DataContext 형식에는 생성된 형식으로 완벽히 정형화된 방식으로 트랜잭션 데이터베이스 업데이트를 보다 쉽게 수행할 수 있는 메서드를 포함합니다.

데이터베이스를 업데이트하려면

  1. 다음 코드에서는 여러 행이 데이터베이스에 추가됩니다.행만 추가하는 경우 InsertOnSubmit을 사용하여 추가할 새 행을 지정할 수 있습니다.여러 행을 삽입하는 경우 컬렉션에 넣은 다음 InsertAllOnSubmit<TSubEntity>을 호출해야 합니다.이러한 방법 중 하나를 호출할 때 데이터베이스가 즉시 변경되지 않습니다.SubmitChanges를 호출하여 변경 내용을 실제로 커밋해야 합니다.기본적으로 SubmitChanges를 호출하기 전에 수행하는 모든 것은 암시적으로 같은 트랜잭션의 일부입니다.

    let newRecord = new dbSchema.ServiceTypes.Table1(Id = 100,
                                                     TestData1 = 35, 
                                                     TestData2 = 2.0,
                                                     Name = "Testing123")
    let newValues =
        [ for i in [1 .. 10] ->
              new dbSchema.ServiceTypes.Table3(Id = 700 + i,
                                               Name = "Testing" + i.ToString(),
                                               Data = i) ]
    // Insert the new data into the database.
    db.Table1.InsertOnSubmit(newRecord)
    db.Table3.InsertAllOnSubmit(newValues)
    try
        db.DataContext.SubmitChanges()
        printfn "Successfully inserted new rows."
    with
       | exn -> printfn "Exception:\n%s" exn.Message
    
  2. 이제 작업을 호출하여 행을 정리합니다.

    // Now delete what was added.
    db.Table1.DeleteOnSubmit(newRecord)
    db.Table3.DeleteAllOnSubmit(newValues)
    try
        db.DataContext.SubmitChanges()
        printfn "Successfully deleted all pending rows."
    with
       | exn -> printfn "Exception:\n%s" exn.Message
    

Transact-SQL 코드 실행

ExecuteCommand 메서드를 DataContext 클래스에서 사용하여 Transact-SQL을 직접 지정할 수도 있습니다.

사용자 지정 SQL 명령을 실행하는 방법

  • 다음 코드는 테이블에 레코드를 삽입하는 SQL 명령을 보내고 테이블에서 레코드를 삭제하는 방법을 보여줍니다.

    try
       db.DataContext.ExecuteCommand("INSERT INTO Table3 (Id, Name, Data) VALUES (102, 'Testing', 55)") |> ignore
    with
       | exn -> printfn "Exception:\n%s" exn.Message
    try //AND Name = 'Testing' AND Data = 55
       db.DataContext.ExecuteCommand("DELETE FROM Table3 WHERE Id = 102 ") |> ignore
    with
       | exn -> printfn "Exception:\n%s" exn.Message
    

전체 데이터 컨텍스트 사용

이전 예제에서 GetDataContext 메서드는 데이터베이스 스키마에 대해 간단한 데이터 컨텍스트라는 것을 가져오는 데 사용되었습니다.많은 멤버를 사용할 수 없기 때문에 쿼리를 생성할 때 간단한 데이터 컨텍스트를 쉽게 사용할 수 있습니다.따라서 IntelliSense에서 특성을 탐색할 때 테이블과 저장 프로시저 같은 데이터베이스 구조에 초점을 맞출 수 있습니다.그러나, 단순화된 데이터 컨텍스트에서 수행할 수 있는 경우에 대한 제한이 있습니다.다른 작업을 수행할 수 있는 기능을 제공하는 전체 데이터 컨텍스트입니다.이는 ServiceTypes에 있으며 사용자가 제공한 경우 DataContext 정적 매개 변수 이름을 갖습니다.제공하지 않으면 데이터 컨텍스트 형식의 이름은 다른 입력을 기준으로 사용자를 대신하여 SqlMetal.exe에서 생성됩니다.전체 데이터 컨텍스트는 DataContext에서 상속되며 Connection 개체 같은 ADO.NET 데이터 형식 및 SQL에서 쿼리를 작성하는 데 사용할 수 있는 ExecuteCommandExecuteQuery 같은 메서드에 대한 참조를 포함하여 기본 클래스의 멤버를 노출하고 트랜잭션을 명시적으로 작업하는 수단입니다.

전체 데이터 컨텍스트를 사용하는 방법

  • 다음 코드는 전체 데이터 컨텍스트 개체를 가져와 데이터베이스에 대해 명령을 직접 실행하는 데 사용하는 방법을 보여줍니다.이 경우 두 명령은 동일한 트랜잭션의 일부로 실행됩니다.

    let dbConnection = testdb.Connection
    let fullContext = new dbSchema.ServiceTypes.MyDatabase(dbConnection)
    dbConnection.Open()
    let transaction = dbConnection.BeginTransaction()
    fullContext.Transaction <- transaction
    try
        let result1 = fullContext.ExecuteCommand("INSERT INTO Table3 (Id, Name, Data) VALUES (102, 'A', 55)")
        printfn "ExecuteCommand Result: %d" result1
        let result2 = fullContext.ExecuteCommand("INSERT INTO Table3 (Id, Name, Data) VALUES (103, 'B', -2)")
        printfn "ExecuteCommand Result: %d" result2
        if (result1 <> 1 || result2 <> 1) then
            transaction.Rollback()
            printfn "Rolled back creation of two new rows."
        else
            transaction.Commit()
            printfn "Successfully committed two new rows."
    with
        | exn -> transaction.Rollback()
                 printfn "Rolled back creation of two new rows due to exception:\n%s" exn.Message
    
    dbConnection.Close()
    

데이터 삭제

이 단계에서는 데이터 테이블에서 행을 삭제하는 방법을 보여줍니다.

데이터베이스에서 행 삭제

  • 이제 지정된 테이블인 Table<TEntity> 클래스의 인스턴스에서 행을 삭제하는 함수를 작성하여 추가된 행을 정리합니다.그런 다음 삭제하려는 모든 행을 찾는 쿼리를 작성하고 쿼리 결과를 deleteRows 함수로 파이프합니다.이 코드는 함수 인수의 부분 응용 프로그램을 제공하는 기능을 활용합니다.

    let deleteRowsFrom (table:Table<_>) rows =
        table.DeleteAllOnSubmit(rows)
    
    query {
        for rows in db.Table3 do
        where (rows.Id > 10)
        select rows
        }
    |> deleteRowsFrom db.Table3
    
    db.DataContext.SubmitChanges()
    printfn "Successfully deleted rows with Id greater than 10 in Table3."
    

테스트 데이터베이스 만들기

이 섹션에서는 이 연습에서 사용할 테스트 데이터베이스를 설정하는 방법을 보여줍니다.

몇 가지 방식으로 데이터베이스를 변경하는 경우 형식 공급자를 재설정해야 합니다.형식 공급자를 재설정하려면 형식 공급자에 포함된 프로젝트를 다시 게시하거나 정리합니다.

테스트 데이터베이스를 만들려면

  1. 서버 탐색기에서 데이터 연결 노드에 대한 바로 가기 메뉴를 열고 연결 추가를 선택합니다.연결 추가 대화 상자가 나타납니다.

  2. 서버 이름 상자에서 관리 액세스 권한이 있는 SQL Server의 인스턴스 이름을 지정 하거나 서버에 액세스할 수 없는 경우 (localdb\v11.0)을 지정합니다.SQL Express LocalDB는 사용자 시스템에서 개발 및 테스트를 위한 단순화된 데이터베이스 서버를 제공합니다.데이터 연결 아래의 서버 탐색기에 새 노드가 만들어집니다.LocalDB에 대한 자세한 내용은 연습: LocalDB 데이터베이스 만들기를 참조하십시오.

  3. 새 연결 노드의 바로 가기 메뉴를 열고 새 쿼리를 선택합니다.

  4. 다음의 SQL 스크립트를 복사하여 쿼리 편집기에 붙여 넣은 다음, 도구 모음에서 실행 단추를 선택하거나 또는 Ctrl+Shift+E 키를 누릅니다.

    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    
    USE [master];
    GO
    
    IF EXISTS (SELECT * FROM sys.databases WHERE name = 'MyDatabase')
                    DROP DATABASE MyDatabase;
    GO
    
    -- Create the MyDatabase database.
    CREATE DATABASE MyDatabase;
    GO
    
    -- Specify a simple recovery model 
    -- to keep the log growth to a minimum.
    ALTER DATABASE MyDatabase 
                    SET RECOVERY SIMPLE;
    GO
    
    USE MyDatabase;
    GO
    
    -- Create the Table1 table.
    CREATE TABLE [dbo].[Table1] (
        [Id]        INT        NOT NULL,
        [TestData1] INT        NOT NULL,
        [TestData2] FLOAT (53) NOT NULL,
        [Name]      NTEXT      NOT NULL,
        PRIMARY KEY CLUSTERED ([Id] ASC)
    );
    
    --Create Table2.
    CREATE TABLE [dbo].[Table2] (
        [Id]        INT        NOT NULL,
        [TestData1] INT        NULL,
        [TestData2] FLOAT (53) NULL,
        [Name]      NTEXT      NOT NULL,
        PRIMARY KEY CLUSTERED ([Id] ASC)
    );
    
    
    --     Create Table3.
    CREATE TABLE [dbo].[Table3] (
        [Id]   INT           NOT NULL,
        [Name] NVARCHAR (50) NOT NULL,
        [Data] INT           NOT NULL,
        PRIMARY KEY CLUSTERED ([Id] ASC)
    );
    GO
    
    CREATE PROCEDURE [dbo].[Procedure1]
           @param1 int = 0,
           @param2 int
    AS
           SELECT TestData1 FROM Table1
    RETURN 0
    GO
    
    -- Insert data into the Table1 table.
    USE MyDatabase
    
    INSERT INTO Table1 (Id, TestData1, TestData2, Name)
    VALUES(1, 10, 5.5, 'Testing1');
    INSERT INTO Table1 (Id, TestData1, TestData2, Name)
    VALUES(2, 20, -1.2, 'Testing2');
    
    --Insert data into the Table2 table.
    INSERT INTO Table2 (Id, TestData1, TestData2, Name)
    VALUES(1, 10, 5.5, 'Testing1');
    INSERT INTO Table2 (Id, TestData1, TestData2, Name)
    VALUES(2, 20, -1.2, 'Testing2');
    INSERT INTO Table2 (Id, TestData1, TestData2, Name)
    VALUES(3, NULL, NULL, 'Testing3');
    
    INSERT INTO Table3 (Id, Name, Data)
    VALUES (1, 'Testing1', 10);
    INSERT INTO Table3 (Id, Name, Data)
    VALUES (2, 'Testing2', 100);
    

참고 항목

작업

연습: DBML 파일에서 F# 형식 생성(F#)

참조

SqlDataConnection 형식 공급자(F#)

쿼리 식(F#)

SqlMetal.exe(코드 생성 도구)

기타 리소스

형식 공급자

LINQ to SQL