並べ替え、フィルタ、検索、編集それにナビゲーションされるDataTableの、データ バインド可能でカスタマイズされたビューを表せます。DataViewのインスタンスはそれのコンストラクタか、DataTableのDefaultViewプロパティから取得できます。並べ替えやフィルタされた結果が必要なだけならば、DataTable.Select()で得られます。
DataView dataView = new DataView(); dataView.Table = dataTable; dataView.Sort = "col1 DESC"; // ソートの基準となる列の名前 dataView.RowFilter = "col2 < 10"; // 行がどのようにフィルタされるかを表す式
パフォーマンスを考慮するならば、ソートやフィルタはコンストラクタで指定します。これをプロパティから設定すると、それらのインデックス (索引) の作成が2度行われることになります。DataView - DataView.cs
public DataView ( System.Data.DataTable table, string RowFilter, string Sort, System.Data.DataViewRowState RowState );DataView(DataTable, String, String, DataViewRowState) - DataView Constructor (System.Data) | Microsoft Learn
型 | プロパティ | 内容 |
---|---|---|
DataTable | Table | ビューのソースであるDataTable |
DataRowView | Item[Int32] | 指定の行 |
string | Sort | 並べ替えに使用する列の名前。既定は空文字列 |
string | RowFilter | 表示する行を決めるフィルタに使用する式。既定は空文字列 |
DataViewRowState | RowStateFilter | 表示する行を決める行の状態フィルタ。既定はCurrentRows |
foreach (DataRowView dataRowView in dataView) { }
ソートの基準となる列名に続けて、昇順ならば"ASC"、降順ならば"DESC"を指定します。順を省略すると昇順となります。複数の列を基準とする場合は、それらをコンマで区切ります。DataView.Sort Property (System.Data) | Microsoft Learn
dataView.Sort = "col1";
次の例の場合、col2で降順に並べ替えられたうえで、col1で昇順に並べ替えられます。
dataView.Sort = "col1 ASC, col2 DESC";
並べ替えの規則は、列のDataColumn.DataTypeプロパティの型に基づいて行われます。よってその型が文字列や数値のとき、データがnullの行は昇順では先に、降順では後に表示されます。
int r1 = String.Compare("a", "b"); // -1 ("a" は "b" より前) int r2 = String.Compare("a", null); // 1 ("a" は null より後) int n1 = 1.CompareTo(2); // -1 (1 は 2 より前) int n2 = 1.CompareTo(null); // 1 (1 は null より後)
表示する行を決めるフィルタで、DataView RowFilter Syntax [C#]にある構文に従って指定します。このフィルタを解除するには、空文字列またはnullを指定します。DataView.RowFilter Property (System.Data) | Microsoft Learn
このRowFilterは、データ バインドしたコントロールにフィルタした結果を表示するために用います。このプロパティは設定する度にインデックスが再構築されるため、パフォーマンスが下がります。特定のクエリの結果を得るのが目的ならば、代わりにFindRows()を呼びます。このメソッドはインデックスの再構築なく実行されます。Find and FindRows - DataView Performance - ADO.NET | Microsoft Learn
dataView.RowFilter = "col1 IN(2,5)";
dataView.RowFilter = "id = 10"; // 特殊文字なし dataView.RowFilter = "$id = 10"; // 特殊文字なし
列名に特殊文字「~ ( ) # \ / = > < + - * % & | ^ ' " [ ]」が含まれるならば、列名を[]で囲みます。そのとき「] \」を含むならば、それらをさらにバックスラッシュでエスケープします。
dataView.RowFilter = "[#id] = 10"; // "#"が特殊文字 dataView.RowFilter = "[[id\]] = 10"; // "["と"]"が特殊文字。さらに"]"をエスケープ
文字列値はシングルクォートで囲みます。もし文字列にシングルクォートが含まれるならば、それを二重にします。
// String values dataView.RowFilter = "Name = 'John'"; // string value dataView.RowFilter = "Name = 'John ''A'''"; // string with single quotes "John 'A'"
数値はどの文字でも囲みません。値はインバリアント (invariant) または英語カルチャでのint.ToString()またはfloat.ToString()の結果と同じとします。
// Number values dataView.RowFilter = "Year = 2008"; // integer value dataView.RowFilter = "Price = 1199.9"; // float value dataView.RowFilter = String.Format(CultureInfo.InvariantCulture.NumberFormat, "Price = {0}", 1199.9f);
日時はシャープで囲みます。その書式はインバリアント (invariant) または英語カルチャでのDateTime.ToString()の結果と同じとします。
// Date values dataView.RowFilter = "Date = #12/31/2008#"; // date value (time is 00:00:00) dataView.RowFilter = "Date = #2008-12-31#"; // also this format is supported dataView.RowFilter = "Date = #12/31/2008 16:44:58#"; // date and time value dataView.RowFilter = String.Format(CultureInfo.InvariantCulture.DateTimeFormat, "Date = #{0}#", new DateTime(2008, 12, 31, 16, 44, 58));
ただしインバリアントなカルチャの書式で取得できるDateTime.ToString(new DateTimeFormatInfo())
にはミリ秒単位の情報が含まれないため、その情報を含む行には一致しません。よってISO 8601準拠の書式で取得できるDateTime.ToString("o")
を用いるのが確実です。
dataView.RowFilter = $"Date = #{dateTime:o}#";
TimeSpanなどのIConvertibleを実装しない型は、文字列などに変換した上で比較します。c# - DataView RowFilter with TimeSpan DataType - Stack Overflow
dataView.RowFilter = "Time = 10"; // System.Data.EvaluateException「System.TimeSpan および System.Int32 で '=' 操作を実行できません。」 dataView.RowFilter = "Time = 'PT10S'"; // System.Data.EvaluateException「System.TimeSpan および System.String で '=' 操作を実行できません。」 dataView.RowFilter = "Convert(Time, 'System.String') = 'PT10S'";
dataView.RowFilter = "Num = 10"; // number is equal to 10 dataView.RowFilter = "Date < #1/1/2008#"; // date is less than 1/1/2008 dataView.RowFilter = "Name <> 'John'"; // string is not equal to 'John' dataView.RowFilter = "Name >= 'Jo'"; // string comparison
文字列に対する不等号は、文字列の相対位置で比較されます。
// Operator IN dataView.RowFilter = "Id IN (1, 2, 3)"; // integer values dataView.RowFilter = "Price IN (1.0, 9.9, 11.5)"; // float values dataView.RowFilter = "Name IN ('John', 'Jim', 'Tom')"; // string values dataView.RowFilter = "Date IN (#12/31/2008#, #1/1/2009#)"; // date time values dataView.RowFilter = "Id NOT IN (1, 2, 3)"; // values not from the list
演算子は大文字/小文字が区別されません。これは他の演算子にも該当します。
ワイルドカードを使用するには、演算子をLIKEとします。ワイルドカードは「*」または「%」を使用でき、いずれでも意味は同じです。
// Operator LIKE dataView.RowFilter = "Name LIKE 'j*'"; // values that start with 'j' dataView.RowFilter = "Name LIKE '%jo%'"; // values that contain 'jo' dataView.RowFilter = "Name NOT LIKE 'j*'"; // values that don't start with 'j'
パターン文字列に特殊文字「* % [ ]」が含まれるならば、それらを[]で囲みます。
dataView.RowFilter = "Name LIKE '[*]*'"; // values that starts with '*' dataView.RowFilter = "Name LIKE '[[]*'"; // values that starts with '['
この演算子はNULLとの組み合わせのみ有効で、DBNullに一致します。c# - how to use DataTable.Select() to select Null/ empty values? - Stack Overflow
dataView.RowFilter = "Name IS NULL"; dataView.RowFilter = "Name IS NOT NULL";
ドキュメントにはありませんが、この演算子はSelectクラスなどで用いられています。
dataView.RowFilter = "City = 'Tokyo' AND (Age < 20 OR Age > 60)";
dataView.RowFilter = "MotherAge - Age < 20"; // people with young mother dataView.RowFilter = "Age % 10 = 0"; // people with decennial birthday
親テーブルを対象にフィルタを適用するにはParent.列名、子テーブルならばChild.列名の形式で指定します。また、子の関連は複数の行を返すことがあるため、集合関数 (aggregate function) 内に含めます。DataColumn.Expression Property (System.Data) | Microsoft Learn
dataView.RowFilter = "Sum(Child.col1) < 10";
このときテーブルが複数の子テーブルを持つならば、Child(関連名).列名のように関連名も指定します。
dataView.RowFilter = "Sum(Child(relation1).col2) < 10";
Sum | Sum |
Avg | Average |
Min | Minimum |
Max | Maximum |
Count | Count |
StDev | Statistical standard deviation (標準偏差) |
Var | Statistical variance (分散) |
子テーブルに表示を制御するための列を追加しておき、その列の値が孫テーブルの値で決定されるようにExpressionを指定しておきます。そしてその列を条件に、親テーブルに式を設定します。vb.net - ADO.NET - Accessing Each DataView in DataViewManager - Stack Overflow
DataColumn column = childTable.Columns.Add("visible", typeof(bool)); column.Expression = "IIF(Sum(Child.col1) < 10, 1, 0)"; dataView.RowFilter = "Max(Child.visible) = 1";
または子テーブルでその子テーブルをフィルタし、関連させている列から親テーブルをフィルタする方法もありますが、このような複雑な条件ではLINQを用いた方が効率的です。
DataRow[] childRows = childTable.Select("Sum(Child.col1) < 10"); List<int> ids = new List<int>(); foreach (DataRow row in childRows) { ids.Add(row.Field<int>("id")); } dataView.RowFilter = $"id IN ({String.Join(",", ids)})";
もしくはDataView.Tableを子テーブルとして、その結果のDataRowView.Row.GetParentRow()で親テーブルのDataRowを取得します。この方法ならば、階層の深い孫テーブル以下にも適用できます。
より複雑な条件でフィルタを適用するには、LINQ to DataSetを用います。たとえばDataViewで、
DataView dataView = new DataView(); dataView.Table = dataTable; dataView.RowFilter = "col1 > 1"; foreach (DataRowView dataRowView in dataView) { Console.Write(dataRowView["id"]); }
とする処理は、LINQでは次のようにします。
IEnumerable<DataRow> query = from row in dataTable.AsEnumerable() where row.Field<int>("col1") > 1 select row; foreach (DataRow dataRow in query) { Console.Write(dataRow["id"]); }
下表のDataViewRowStateの組み合わせで指定します。
列挙子 | 数値 | 内容 |
---|---|---|
None | 0 | None. |
Unchanged | 2 | An unchanged row. |
Added | 4 | A new row. |
Deleted | 8 | A deleted row. |
ModifiedCurrent | 16 | 変更された元のデータの、現在のバージョン。ModifiedOriginalを参照
DataRowState.Modified と等値 ModifiedCurrent - DataViewRowState.cs |
ModifiedOriginal | 32 | 変更されたデータの、元のバージョン
(Although the data has since been modified, it is available as ModifiedCurrent) |
CurrentRows | 22 | Current rows including unchanged, new, and modified rows. By default, DataViewRowState is set to CurrentRows.
|
OriginalRows | 42 | Original rows including unchanged and deleted rows.
|
メソッド | 機能 |
---|---|
AddNew() | ビューに新しい行を追加する |
ToTable() | 現在のビューに存在する行をもとに、新しいテーブルを作成して返す |
Find(Object) | 指定の並べ替えキー (sort key) に一致した、最初の行のインデックスを取得できる |
FindRows(Object) | 指定の並べ替えキー (sort key) に一致した、DataRowViewの配列を取得できる |
public virtual System.Data.DataRowView AddNew ();DataView.AddNew Method (System.Data) | Microsoft Learn
Tableプロパティがnullだと、NullReferenceExceptionが発生し行の追加に失敗します。
Sortで指定されている列でkeyに一致した、DataRowViewの配列を取得できます。
public System.Data.DataRowView[] FindRows (object key);FindRows(Object) - DataView.FindRows Method (System.Data) | Microsoft Learn
Sortプロパティで並べ替え列を指定していないと、「Find は、並べ替え順序に基づいて行を検索しますが、並べ替え順序が指定されていません。」としてArgumentExceptionが投げられます。
DataTable dataTable = new DataTable();
dataTable.Columns.Add("col1");
dataTable.Columns.Add("col2");
dataTable.Rows.Add("a", "b");
dataTable.Rows.Add("c", "d");
DataView dataView = new DataView(dataTable);
dataView.Sort = "col2";
DataRowView[] found = dataView.FindRows("d");
// found[0].Row.ItemArray "c", "d"