by WebSurfer
16. December 2022 17:45
DataRowExtensions.Field メソッドを使って DataRow から値を取得すると、対象のセルの値が DBNull の場合は null を返してくれるという話を書きます。
例えば、以下のような NULL が含まれる SQL Server のテーブルから SqlDataAdapter クラスの Fill メソッドを使って DataTable を作成したとします。

そうすると SQL Server DB のフィールドが NULL の場合、DataTable の DataRow の当該セルには DBNull オブジェクトへの参照が代入されます。
下の画像は、上の SQL Server のテーブルの 3 行目(Name と Date が NULL)から取得した DataRow を Visual Studio 2022 のデバッガで開いても見たもので、SQL Server の NULL は DataRow では DBNull になっています。

この DataTable の DataRow の例えば Name 列から値を取得する場合、DataRow.Item プロパティを使って以下のようにすると、
string name = (string)row["Name"];
当該セルに DBNull が入っている場合は InvalidCastException がスローされ、"Unable to cast object of type 'System.DBNull' to type 'System.String'." というエラーメッセージが出ます。
なので、row["Name"] が DBNull か否かを判定して処理を分けるようなコードを書くことになります。例えば以下のようにする必要があります。
string name = (row["Name"] is DBNull) ? null : (string)row["Name"];
一方、DataRowExtensions.Field メソッドを使って以下のよう書くと、当該セルが DBNull の場合は null が返されます。キャストも不要です。
string name = row.Field<string>("Name");
検証に使ったコードを以下に載せておきます。Visual Studio 2022 を使って作った .NET 6.0 のコンソールアプリケーションです。デフォルトで null 許容参照型が有効になりますので string ではなく string? としています。
using System.Data;
using System.Data.SqlClient;
var selectQuery = "SELECT [Id],[Name],[Price],[Date] FROM [Sample]";
var connString = "接続文字列";
var table = new DataTable();
using (var connection = new SqlConnection(connString))
{
using (var command = new SqlCommand(selectQuery, connection))
{
var adapter = new SqlDataAdapter(command);
adapter.Fill(table);
}
}
var list = table.AsEnumerable()
.Select(row => new Sample
{
Id = row.Field<int>("Id"),
Name = row.Field<string?>("Name"),
Price = row.Field<decimal?>("Price"),
Date = row.Field<DateTime?>("Date")
})
.ToList();
foreach (var c in list)
{
Console.WriteLine($"ID: {c.Id}, Name: {c.Name ?? "null"}, " +
$"Price: {c.Price?.ToString() ?? "null"}, " +
$"Date: {c.Date?.ToString() ?? "null"}");
}
public class Sample
{
public int Id { get; set; }
public string? Name { get; set; }
public decimal? Price { get; set; }
public DateTime? Date { get; set; }
}
上のコードの実行結果は以下の通りとなります。
