C#, ASP.NET、データベースにおける "Unable to cast object of type 'System.DBNull' to type 'System.String'" エラーの解決策 - サンプルコード
C#, ASP.NET、データベースにおける "Unable to cast object of type 'System.DBNull' to type 'System.String'" エラーの解決策
このエラーは、データベースから取得した値を文字列型に変換しようとすると発生します。データベースには NULL 値を表す System.DBNull
型があり、文字列型とは異なるため、直接的に変換することはできません。
原因
このエラーは、主に以下の2つの原因で発生します。
- データベースカラムのデータ型とC#側の変数の型が一致していない
- NULL 値の処理が適切に行われていない
解決策
以下の方法で解決できます。
データ型の一致
データベースカラムのデータ型とC#側の変数の型が一致していることを確認してください。例えば、データベースカラムが varchar
型の場合は、C#側の変数は string
型にする必要があります。
NULL 値の処理
NULL 値の可能性を考慮し、適切な処理を行う必要があります。以下に、一般的な方法を紹介します。
- null 合体演算子 (
??
)
string value = dataReader["columnName"] ?? "";
この式は、dataReader["columnName"]
が DBNull
の場合は空文字列を代入します。
- 条件分岐
if (dataReader["columnName"] != DBNull.Value)
{
string value = (string)dataReader["columnName"];
}
else
{
string value = "";
}
- Convert クラス
string value = Convert.ToString(dataReader["columnName"]);
この式は、dataReader["columnName"]
を文字列型に変換しようとします。ただし、DBNull
の場合は例外が発生しますので、上記のいずれかの方法と組み合わせて使用する必要があります。
ASP.NETの場合
ASP.NETでは、以下の方法で NULL 値の処理を簡単に行うことができます。
- DataBinder コントロール
<asp:Label runat="server" ID="Label1" Text='<%# Eval("columnName") %>'></asp:Label>
このコードは、columnName
カラムの値をラベルに表示します。Eval
メソッドは、NULL 値の場合は空文字列を返します。
- Razor シンタックス
@if (Model.columnName != null)
{
<p>@Model.columnName</p>
}
else
{
<p>データがありません</p>
}
このコードは、columnName
プロパティの値が NULL でない場合のみ、値をパラグラフ要素に表示します。
上記の解決策以外にも、状況に応じて様々な方法があります。適切な方法を選択するために、エラーが発生している箇所を分析し、データベースのスキーマとアプリケーションのロジックを理解することが重要です。
このシナリオでは、以下のテーブルを持つ Northwind
データベースを使用します。
CREATE TABLE Customers (
CustomerID int PRIMARY KEY,
CompanyName nvarchar(128),
ContactName nvarchar(64)
);
このテーブルから CompanyName
カラムの値を取得し、ASP.NETページに表示するアプリケーションを作成します。
コード例
C# コード
using System;
using System.Data.SqlClient;
public class Customer
{
public int CustomerID { get; set; }
public string CompanyName { get; set; }
public string ContactName { get; set; }
}
public class CustomersDAO
{
public static List<Customer> GetCustomers()
{
List<Customer> customers = new List<Customer>();
using (SqlConnection connection = new SqlConnection("Server=localhost;Database=Northwind;Integrated Security=SSPI"))
{
connection.Open();
using (SqlCommand command = new SqlCommand("SELECT CustomerID, CompanyName, ContactName FROM Customers", connection))
{
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
Customer customer = new Customer();
customer.CustomerID = (int)reader["CustomerID"];
// NULL 値の処理
if (reader["CompanyName"] != DBNull.Value)
{
customer.CompanyName = (string)reader["CompanyName"];
}
else
{
customer.CompanyName = "";
}
customer.ContactName = (string)reader["ContactName"];
customers.Add(customer);
}
}
}
}
return customers;
}
}
public partial class Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
List<Customer> customers = CustomersDAO.GetCustomers();
GridView gridView = new GridView();
gridView.DataSource = customers;
gridView.DataBind();
Controls.Add(gridView);
}
}
ASP.NETページ
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="WebApplication1.Default" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Customers</title>
</head>
<body>
<form id="form1" runat="server">
<asp:GridView runat="server" ID="GridView1"></asp:GridView>
</form>
</body>
</html>
説明
- C# コード
CustomersDAO
クラス: データベースから顧客情報を取得するメソッドGetCustomers
を定義します。Default
クラス:
- ASP.NETページ
string value = dataReader["columnName"] ?? "";
例
List<Customer> customers = CustomersDAO.GetCustomers();
GridView gridView = new GridView();
gridView.DataSource = customers;
gridView.Columns.Add(new BoundField(DataField = "CustomerID", DataHeaderText = "Customer ID"));
gridView.Columns.Add(new BoundField(DataField = "CompanyName", DataHeaderText = "Company Name"));
gridView.Columns.Add(new BoundField(DataField = "ContactName", DataHeaderText = "Contact Name"));
gridView.DataBind();
Controls.Add(gridView);
テンプレートフィールド
ASP.NET GridView コントロールのテンプレートフィールドを使用して、NULL 値に独自の処理を適用できます。
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="WebApplication1.Default" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Customers</title>
</head>
<body>
<form id="form1" runat="server">
<asp:GridView runat="server" ID="GridView1">
<Columns>
<asp:BoundField DataField="CustomerID" DataHeaderText="Customer ID" />
<asp:TemplateField DataField="CompanyName" HeaderText="Company Name">
<ItemTemplate>
<%# Eval("CompanyName") ?? "N/A" %>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="ContactName" DataHeaderText="Contact Name" />
</Columns>
</asp:GridView>
</form>
</body>
</html>
ASP.NET MVC や Razor Pages では、Razor シンタックスを使用して、NULL 値の処理をより簡潔に記述できます。
@model List<Customer>
@foreach (var customer in Model)
{
<tr>
<td>@customer.CustomerID</td>
<td>@customer.CompanyName ?? "N/A"</td>
<td>@customer.ContactName</td>
</tr>
}
ユーティリティメソッド
NULL 値の処理を共通化するために、ユーティリティメソッドを作成できます。
public static string GetStringOrDefault(object value)
{
if (value == DBNull.Value)
{
return "";
}
else
{
return value.ToString();
}
}
List<Customer> customers = CustomersDAO.GetCustomers();
GridView gridView = new GridView();
gridView.DataSource = customers;
gridView.Columns.Add(new BoundField(DataField = "CustomerID", DataHeaderText = "Customer ID"));
gridView.Columns.Add(new BoundField(DataField = "CompanyName", DataHeaderText = "Company Name", DataFormatString="{0:0}"));
gridView.Columns.Add(new BoundField(DataField = "ContactName", DataHeaderText = "Contact Name"));
gridView.DataBind();
Controls.Add(gridView);
データアクセスライブラリの使用
Entity Framework Coreなどのデータアクセスライブラリを使用すると、NULL 値の処理を自動的に行うことができます。
using (var context = new NorthwindContext())
{
var customers = context.Customers.ToList();
GridView gridView = new GridView();
gridView.DataSource = customers;
gridView.Columns.Add(new BoundField(DataField = "CustomerID", DataHeaderText = "Customer ID"));
gridView.Columns.Add(new BoundField(DataField = "CompanyName", DataHeaderText = "Company Name"));
gridView.Columns.Add(new BoundField(DataField = "ContactName", DataHeaderText = "Contact Name"));
c# asp.net database