DataView로 필터링(LINQ to DataSet)

특정 조건을 사용하여 데이터를 필터링한 다음 UI 컨트롤을 통해 클라이언트에 데이터를 제공하는 기능은 데이터 바인딩의 중요한 기능입니다. DataView에서는 데이터를 필터링하여 특정 필터 조건을 충족하는 데이터 행의 하위 집합을 반환하는 여러 가지 방법을 제공합니다. 문자열 기반 필터링 기능 외에도, DataView는 필터링 기준에 LINQ 식을 사용하는 기능도 제공합니다. LINQ 식을 사용하면 문자열 기반 필터링보다 훨씬 더 복잡하고 강력한 필터링 작업을 수행할 수 있습니다.

DataView를 사용하여 데이터를 필터링하는 방법에는 두 가지가 있습니다.

  • Where 절이 있는 LINQ to DataSet 쿼리에서 DataView를 만듭니다.

  • DataView의 기존 문자열 기반 필터링 기능을 사용합니다.

필터링 정보가 있는 쿼리에서 DataView 만들기

DataView 개체는 LINQ to DataSet 쿼리에서 만들 수 있습니다. 해당 쿼리에 Where 절이 있으면 쿼리의 필터링 정보를 사용하여 DataView를 만듭니다. Where 절의 식은 DataView에 포함되는 데이터 행을 확인하는 데 사용되며 필터의 기본 요소입니다.

식 기반 필터는 간단한 문자열 기반 필터에 비해 강력하고 복잡한 필터링 기능을 제공합니다. 문자열 기반 필터와 식 기반 필터는 함께 사용할 수 없습니다. RowFilter를 쿼리에서 만든 후에 문자열 기반 DataView를 설정하면 쿼리에서 유추된 식 기반 필터가 지워집니다.

참고 항목

대부분의 경우 필터링에 사용되는 식은 파생 작용이 없어야 하고 명확해야 합니다. 또한 필터링 작업이 여러 번 실행될 수 있으므로 식에는 실행 집합 번호에 따라 달라지는 논리가 없어야 합니다.

예시

다음 예제에서는 SalesOrderDetail 테이블에 대해 수량이 2보다 크고 6보다 작은 주문을 쿼리한 다음 해당 쿼리에서 DataView를 만들고 DataViewBindingSource에 바인딩합니다.

DataTable orders = _dataSet.Tables["SalesOrderDetail"];

EnumerableRowCollection<DataRow> query = from order in orders.AsEnumerable()
                                         where order.Field<short>("OrderQty") > 2 && order.Field<short>("OrderQty") < 6
                                         select order;

DataView view = query.AsDataView();

bindingSource1.DataSource = view;
Dim orders As DataTable = dataSet.Tables("SalesOrderDetail")

Dim query = _
    From order In orders.AsEnumerable() _
    Where order.Field(Of Int16)("OrderQty") > 2 And _
          order.Field(Of Int16)("OrderQty") < 6 _
    Select order

Dim view As DataView = query.AsDataView()
bindingSource1.DataSource = view

예시

다음 예제에서는 2001년 6월 6일 이후 주문에 대한 쿼리에서 DataView를 만듭니다.

DataTable orders = _dataSet.Tables["SalesOrderHeader"];

EnumerableRowCollection<DataRow> query = from order in orders.AsEnumerable()
                                         where order.Field<DateTime>("OrderDate") > new DateTime(2002, 6, 1)
                                         select order;

DataView view = query.AsDataView();

bindingSource1.DataSource = view;
Dim orders As DataTable = dataSet.Tables("SalesOrderHeader")

Dim query = _
    From order In orders.AsEnumerable() _
    Where order.Field(Of DateTime)("OrderDate") > New DateTime(2002, 6, 1) _
    Select order

Dim view As DataView = query.AsDataView()
bindingSource1.DataSource = view

예시

필터링을 정렬과 결합할 수도 있습니다. 다음 예제에서는 성이 "S"로 시작하는 연락처를 성과 이름순으로 정렬하는 쿼리에서 DataView를 만듭니다.

DataTable contacts = _dataSet.Tables["Contact"];

EnumerableRowCollection<DataRow> query = from contact in contacts.AsEnumerable()
                                         where contact.Field<string>("LastName").StartsWith("S")
                                         orderby contact.Field<string>("LastName"), contact.Field<string>("FirstName")
                                         select contact;

DataView view = query.AsDataView();

bindingSource1.DataSource = view;
dataGridView1.AutoResizeColumns();

Dim contacts As DataTable = dataSet.Tables("Contact")

Dim query = _
    From contact In contacts.AsEnumerable() _
    Where contact.Field(Of String)("LastName").StartsWith("S") _
    Order By contact.Field(Of String)("LastName"), contact.Field(Of String)("FirstName") _
    Select contact

Dim view As DataView = query.AsDataView()
bindingSource1.DataSource = view
dataGridView1.AutoResizeColumns()

예시

다음 예제에서는 SoundEx 알고리즘을 사용하여 성이 "Zhu"와 비슷한 연락처를 찾습니다. SoundEx 알고리즘은 SoundEx 메서드에서 구현됩니다.

DataTable contacts = _dataSet.Tables["Contact"];

var soundExCode = SoundEx("Zhu");

EnumerableRowCollection<DataRow> query = from contact in contacts.AsEnumerable()
                                         where SoundEx(contact.Field<string>("LastName")) == soundExCode
                                         select contact;

DataView view = query.AsDataView();

bindingSource1.DataSource = view;
dataGridView1.AutoResizeColumns();
Dim contacts As DataTable = dataSet.Tables("Contact")
Dim soundExCode As String = SoundEx("Zhu")

Dim query = _
    From contact In contacts.AsEnumerable() _
    Where SoundEx(contact.Field(Of String)("LastName")) = soundExCode _
    Select contact

Dim view As DataView = query.AsDataView()
bindingSource1.DataSource = view
dataGridView1.AutoResizeColumns()

U.S. Census Bureau에서 개발한 SoundEx는 영어 발음의 소리를 기준으로 이름을 인덱싱하는 데 사용되는 음성 알고리즘입니다. SoundEx 메서드는 하나의 영어 문자 뒤에 숫자 3개가 있는 형식으로 구성된 이름에 대한 4문자 코드를 반환합니다. 영어 문자는 이름의 첫 번째 문자이고 숫자는 이름의 나머지 자음을 인코딩합니다. 발음이 비슷한 이름은 같은 SoundEx 코드를 공유합니다. 이전 예제의 SoundEx 메서드에 사용된 SoundEx 구현은 다음과 같습니다.

static string SoundEx(string word)
{
    // The length of the returned code.
    const int length = 4;

    // Value to return.
    var value = "";

    // The size of the word to process.
    var size = word.Length;

    // The word must be at least two characters in length.
    if (size > 1)
    {
        // Convert the word to uppercase characters.
        word = word.ToUpper(CultureInfo.InvariantCulture);

        // Convert the word to a character array.
        var chars = word.ToCharArray();

        // Buffer to hold the character codes.
        var buffer = new StringBuilder
        {
            Length = 0
        };

        // The current and previous character codes.
        var prevCode = 0;
        var currCode = 0;

        // Add the first character to the buffer.
        buffer.Append(chars[0]);

        // Loop through all the characters and convert them to the proper character code.
        for (var i = 1; i < size; i++)
        {
            switch (chars[i])
            {
                case 'A':
                case 'E':
                case 'I':
                case 'O':
                case 'U':
                case 'H':
                case 'W':
                case 'Y':
                    currCode = 0;
                    break;
                case 'B':
                case 'F':
                case 'P':
                case 'V':
                    currCode = 1;
                    break;
                case 'C':
                case 'G':
                case 'J':
                case 'K':
                case 'Q':
                case 'S':
                case 'X':
                case 'Z':
                    currCode = 2;
                    break;
                case 'D':
                case 'T':
                    currCode = 3;
                    break;
                case 'L':
                    currCode = 4;
                    break;
                case 'M':
                case 'N':
                    currCode = 5;
                    break;
                case 'R':
                    currCode = 6;
                    break;
            }

            // Check if the current code is the same as the previous code.
            if (currCode != prevCode)
            {
                // Check to see if the current code is 0 (a vowel); do not process vowels.
                if (currCode != 0)
                {
                    buffer.Append(currCode);
                }
            }
            // Set the previous character code.
            prevCode = currCode;

            // If the buffer size meets the length limit, exit the loop.
            if (buffer.Length == length)
            {
                break;
            }
        }
        // Pad the buffer, if required.
        size = buffer.Length;
        if (size < length)
        {
            buffer.Append('0', length - size);
        }

        // Set the value to return.
        value = buffer.ToString();
    }
    // Return the value.
    return value;
}
Private Function SoundEx(ByVal word As String) As String

    Dim length As Integer = 4
    ' Value to return
    Dim value As String = ""
    ' Size of the word to process
    Dim size As Integer = word.Length
    ' Make sure the word is at least two characters in length
    If (size > 1) Then
        ' Convert the word to all uppercase
        word = word.ToUpper(System.Globalization.CultureInfo.InvariantCulture)
        ' Convert the word to character array for faster processing
        Dim chars As Char() = word.ToCharArray()
        ' Buffer to build up with character codes
        Dim buffer As StringBuilder = New StringBuilder()
        ' The current and previous character codes
        Dim prevCode As Integer = 0
        Dim currCode As Integer = 0
        ' Append the first character to the buffer
        buffer.Append(chars(0))
        ' Loop through all the characters and convert them to the proper character code
        For i As Integer = 1 To size - 1
            Select Case chars(i)

                Case "A", "E", "I", "O", "U", "H", "W", "Y"
                    currCode = 0

                Case "B", "F", "P", "V"
                    currCode = 1

                Case "C", "G", "J", "K", "Q", "S", "X", "Z"
                    currCode = 2

                Case "D", "T"
                    currCode = 3

                Case "L"
                    currCode = 4

                Case "M", "N"
                    currCode = 5

                Case "R"
                    currCode = 6
            End Select

            ' Check to see if the current code is the same as the last one
            If (currCode <> prevCode) Then

                ' Check to see if the current code is 0 (a vowel); do not process vowels
                If (currCode <> 0) Then
                    buffer.Append(currCode)
                End If
            End If
            ' Set the new previous character code
            prevCode = currCode
            ' If the buffer size meets the length limit, then exit the loop
            If (buffer.Length = length) Then
                Exit For
            End If
        Next
        ' Pad the buffer, if required
        size = buffer.Length
        If (size < length) Then
            buffer.Append("0", (length - size))
        End If
        ' Set the value to return
        value = buffer.ToString()
    End If
    ' Return the value
    Return value
End Function

RowFilter 속성 사용

DataView의 기존 문자열 기반 필터링 기능은 LINQ to DataSet 컨텍스트에서 계속 사용할 수 있습니다. 문자열 기반 RowFilter 필터링에 대한 자세한 내용은 데이터 정렬 및 필터링을 참조하세요.

다음 예제에서는 Contact 테이블에서 DataView를 만든 다음 연락처의 성이 "Zhu"인 행을 반환하도록 RowFilter 속성을 설정합니다.

DataTable contacts = _dataSet.Tables["Contact"];

DataView view = contacts.AsDataView();

view.RowFilter = "LastName='Zhu'";

bindingSource1.DataSource = view;
dataGridView1.AutoResizeColumns();
Dim contacts As DataTable = dataSet.Tables("Contact")

Dim view As DataView = contacts.AsDataView()
view.RowFilter = "LastName='Zhu'"
bindingSource1.DataSource = view
dataGridView1.AutoResizeColumns()

DataTable 또는 LINQ to DataSet 쿼리에서 DataView를 만든 후, RowFilter 속성을 사용하여 열 값을 기준으로 행의 하위 집합을 지정할 수 있습니다. 문자열 기반 필터와 식 기반 필터는 함께 사용할 수 없습니다. RowFilter 속성을 설정하면 LINQ to DataSet 쿼리에서 유추된 필터 식이 지워지며, 이 필터 식은 재설정할 수 없습니다.

DataTable contacts = _dataSet.Tables["Contact"];

EnumerableRowCollection<DataRow> query = from contact in contacts.AsEnumerable()
                                         where contact.Field<string>("LastName") == "Hernandez"
                                         select contact;

DataView view = query.AsDataView();

bindingSource1.DataSource = view;
dataGridView1.AutoResizeColumns();

view.RowFilter = "LastName='Zhu'";
Dim contacts As DataTable = dataSet.Tables("Contact")

Dim query = _
    From contact In contacts.AsEnumerable() _
    Where contact.Field(Of String)("LastName") = "Hernandez" _
    Select contact

Dim view As DataView = query.AsDataView()
bindingSource1.DataSource = view

dataGridView1.AutoResizeColumns()
view.RowFilter = "LastName='Zhu'"

데이터의 하위 집합에 대한 동적 뷰를 제공하는 것과는 반대로 데이터에 대한 특정 쿼리 결과를 반환하려는 경우 Find 속성을 설정하는 대신 FindRowsDataView 또는 RowFilter 메서드를 사용할 수 있습니다. RowFilter 속성은 바인딩된 컨트롤이 필터링된 결과를 표시하는 데이터 바인딩된 애플리케이션에 가장 적합합니다. RowFilter 속성을 설정하면 데이터의 인덱스가 다시 작성되므로 애플리케이션에 오버헤드가 발생하여 성능이 저하됩니다. FindFindRows 메서드는 인덱스를 다시 작성하지 않고 현재 인덱스를 사용합니다. Find 또는 FindRows를 한 번만 호출할 경우에는 기존 DataView를 사용해야 합니다. Find 또는 FindRows를 여러 번 호출할 경우에는 새 DataView를 만들어서 검색하려는 열의 인덱스를 다시 작성한 다음 Find 또는 FindRows 메서드를 호출해야 합니다. FindFindRows 메서드에 대한 자세한 내용은 행 찾기DataView 성능을 참조하세요.

필터 지우기

필터링이 설정된 후 DataView 속성을 사용하여 RowFilter의 필터를 지울 수 있습니다. DataView의 필터는 두 가지 방법으로 지울 수 있습니다.

  • RowFilter 속성을 null로 설정합니다.

  • RowFilter 속성을 빈 문자열로 설정합니다.

예시

다음 예제에서는 쿼리에서 DataView를 만든 다음 RowFilter 속성을 null로 설정하여 필터를 지웁니다.

DataTable orders = _dataSet.Tables["SalesOrderHeader"];

EnumerableRowCollection<DataRow> query = from order in orders.AsEnumerable()
                                         where order.Field<DateTime>("OrderDate") > new DateTime(2002, 11, 20)
                                            && order.Field<decimal>("TotalDue") < new decimal(60.00)
                                         select order;

DataView view = query.AsDataView();

bindingSource1.DataSource = view;

view.RowFilter = null;
Dim orders As DataTable = dataSet.Tables("SalesOrderHeader")

Dim query = _
    From order In orders.AsEnumerable() _
    Where order.Field(Of DateTime)("OrderDate") > New DateTime(2002, 11, 20) _
        And order.Field(Of Decimal)("TotalDue") < New Decimal(60.0) _
    Select order

Dim view As DataView = query.AsDataView()
bindingSource1.DataSource = view
view.RowFilter = Nothing

예시

다음 예제에서는 테이블에서 DataView를 만들고, RowFilter 속성을 설정한 다음 RowFilter 속성을 빈 문자열로 설정하여 필터를 지웁니다.

DataTable contacts = _dataSet.Tables["Contact"];

DataView view = contacts.AsDataView();

view.RowFilter = "LastName='Zhu'";

bindingSource1.DataSource = view;
dataGridView1.AutoResizeColumns();

// Clear the row filter.
view.RowFilter = "";
Dim contacts As DataTable = dataSet.Tables("Contact")

Dim view As DataView = contacts.AsDataView()
view.RowFilter = "LastName='Zhu'"
bindingSource1.DataSource = view
dataGridView1.AutoResizeColumns()

' Clear the row filter.
view.RowFilter = ""

참고 항목