Simplifying SQL Data Retrieval with SafeGetT Extension Method in C#
When working with SQL data in C#, developers often need to handle data retrieval from an IDataReader
safely, accounting for potential null values or missing columns. In this article we will implement a SqlDataExtensions
static class that provides a useful extension method called SafeGetT
that simplifies this process by safely retrieving typed data from an IDataReader
with proper error handling.
Overview of SafeGetT
The SafeGetT
extension method extends IDataReader
to retrieve a value from a specified column and cast it to the desired type T
. It handles common issues such as:
- Invalid or empty column names
- Missing columns
- Null database values
- Type conversion errors
If any error occurs, it returns default(T)
(e.g., null
for reference types, 0
for integers, etc.), ensuring the application remains stable.
Code Implementation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public static class SqlDataExtensions
{
public static T SafeGetT<T>(this IDataReader reader, string columnName)
{
if (!string.IsNullOrEmpty(columnName))
{
try
{
var columnIndex = reader.GetOrdinal(columnName);
if (!reader.IsDBNull(columnIndex))
{
return (T)reader[columnName];
}
}
catch
{
return default(T);
}
}
return default(T);
}
}
Example Usage
Below is an example of how to use SafeGetT
to retrieve data from a SQL query result:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
using System.Data;
using System.Data.SqlClient;
class Program
{
static void Main()
{
using (var connection = new SqlConnection("your_connection_string"))
{
connection.Open();
var command = new SqlCommand("SELECT Id, Name, Price FROM Products", connection);
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
int id = reader.SafeGetT<int>("Id");
string name = reader.SafeGetT<string>("Name");
decimal price = reader.SafeGetT<decimal>("Price");
Console.WriteLine($"Product: {id}, {name}, ${price}");
}
}
}
}
}
In this example, SafeGetT
retrieves the Id
(int), Name
(string), and Price
(decimal) from the Products
table. If the Price
column is missing or contains a null value, SafeGetT<decimal>
returns 0.0m
instead of throwing an exception.
Unit Test
To ensure the SafeGetT
method works as expected, below is a unit test using MSTest and Moq to mock an IDataReader
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using System.Data;
[TestClass]
public class SqlDataExtensionsTests
{
[TestMethod]
public void SafeGetT_ValidColumnWithValue_ReturnsCorrectValue()
{
// Arrange
var readerMock = new Mock<IDataReader>();
readerMock.Setup(r => r.GetOrdinal("Name")).Returns(0);
readerMock.Setup(r => r.IsDBNull(0)).Returns(false);
readerMock.Setup(r => r["Name"]).Returns("TestProduct");
// Act
string result = readerMock.Object.SafeGetT<string>("Name");
// Assert
Assert.AreEqual("TestProduct", result);
}
[TestMethod]
public void SafeGetT_NullColumnName_ReturnsDefault()
{
// Arrange
var readerMock = new Mock<IDataReader>();
// Act
string result = readerMock.Object.SafeGetT<string>(null);
// Assert
Assert.IsNull(result);
}
[TestMethod]
public void SafeGetT_ColumnNotFound_ReturnsDefault()
{
// Arrange
var readerMock = new Mock<IDataReader>();
readerMock.Setup(r => r.GetOrdinal("NonExistent")).Throws(new IndexOutOfRangeException());
// Act
int result = readerMock.Object.SafeGetT<int>("NonExistent");
// Assert
Assert.AreEqual(0, result);
}
}
This test suite verifies:
- Correct value retrieval for a valid column with data.
- Proper handling of a null column name.
- Graceful handling of a non-existent column.
Benefits
- Safety: Prevents exceptions from null values or missing columns.
- Simplicity: Reduces boilerplate code for data retrieval.
- Flexibility: Works with any type
T
that can be cast from the reader’s data.
Conclusion
The SafeGetT
extension method is a valuable tool for C# developers working with SQL data. By incorporating it into your data access layer, you can write cleaner, more robust code that gracefully handles edge cases. The provided example and unit tests demonstrate its practical application and reliability.