Skip to main content

C# DataSet and DataTable

When working with databases in C#, ADO.NET provides powerful components to manage data efficiently. Among these components, DataSet and DataTable stand out as essential tools for in-memory data manipulation.

Introduction to DataSet and DataTable

A DataSet is an in-memory representation of relational data that consists of a collection of DataTable objects and the relationships between them. Think of it as an in-memory database that allows you to work with data disconnected from its source.

A DataTable, on the other hand, represents a single table of in-memory data. It contains collections of DataRow and DataColumn objects that store and define the data and its structure.

Creating and Working with DataTable

Creating a Simple DataTable

Let's start by creating a basic DataTable:

csharp
using System;
using System.Data;

class Program
{
static void Main()
{
// Create a new DataTable
DataTable customers = new DataTable("Customers");

// Add columns
customers.Columns.Add("ID", typeof(int));
customers.Columns.Add("Name", typeof(string));
customers.Columns.Add("Email", typeof(string));
customers.Columns.Add("JoinDate", typeof(DateTime));

// Display column information
Console.WriteLine("Columns in the Customers table:");
foreach (DataColumn column in customers.Columns)
{
Console.WriteLine($"- {column.ColumnName} ({column.DataType})");
}
}
}

Output:

Columns in the Customers table:
- ID (System.Int32)
- Name (System.String)
- Email (System.String)
- JoinDate (System.DateTime)

Adding Data to a DataTable

Now, let's add some rows to our DataTable:

csharp
// Add rows
customers.Rows.Add(1, "John Doe", "[email protected]", DateTime.Parse("2022-01-15"));
customers.Rows.Add(2, "Jane Smith", "[email protected]", DateTime.Parse("2022-02-20"));
customers.Rows.Add(3, "Bob Johnson", "[email protected]", DateTime.Parse("2022-03-10"));

// Display the data
Console.WriteLine("\nCustomer Data:");
foreach (DataRow row in customers.Rows)
{
Console.WriteLine($"ID: {row["ID"]}, Name: {row["Name"]}, " +
$"Email: {row["Email"]}, Joined: {((DateTime)row["JoinDate"]).ToShortDateString()}");
}

Output:

Customer Data:
ID: 1, Name: John Doe, Email: [email protected], Joined: 1/15/2022
ID: 2, Name: Jane Smith, Email: [email protected], Joined: 2/20/2022
ID: 3, Name: Bob Johnson, Email: [email protected], Joined: 3/10/2022

Setting Constraints on DataTable

DataTable objects can include constraints to maintain data integrity:

csharp
// Create a DataTable with constraints
DataTable products = new DataTable("Products");

// Add columns
products.Columns.Add("ProductID", typeof(int));
products.Columns.Add("ProductName", typeof(string));
products.Columns.Add("Price", typeof(decimal));
products.Columns.Add("Category", typeof(string));

// Set primary key
products.PrimaryKey = new DataColumn[] { products.Columns["ProductID"] };

// Add a unique constraint
UniqueConstraint uniqueNameConstraint = new UniqueConstraint(
"UniqueProductName", products.Columns["ProductName"]);
products.Constraints.Add(uniqueNameConstraint);

// Add a check constraint for positive prices
products.Columns["Price"].Expression = "Price >= 0";

Console.WriteLine("Products table created with constraints");

Creating and Working with DataSet

Creating a Simple DataSet

A DataSet can contain multiple DataTable objects:

csharp
using System;
using System.Data;

// Create a new DataSet
DataSet companyData = new DataSet("CompanyDatabase");

// Add the existing tables
companyData.Tables.Add(customers);
companyData.Tables.Add(products);

Console.WriteLine($"\nDataSet '{companyData.DataSetName}' contains {companyData.Tables.Count} tables:");
foreach (DataTable table in companyData.Tables)
{
Console.WriteLine($"- {table.TableName}");
}

Output:

DataSet 'CompanyDatabase' contains 2 tables:
- Customers
- Products

Creating Relationships Between Tables

One of the main advantages of a DataSet is the ability to define relationships between tables:

csharp
// Create a new table for orders
DataTable orders = new DataTable("Orders");
orders.Columns.Add("OrderID", typeof(int));
orders.Columns.Add("CustomerID", typeof(int));
orders.Columns.Add("OrderDate", typeof(DateTime));
orders.Columns.Add("TotalAmount", typeof(decimal));

// Set primary key
orders.PrimaryKey = new DataColumn[] { orders.Columns["OrderID"] };

// Add to dataset
companyData.Tables.Add(orders);

// Create a relationship between Customers and Orders
DataRelation customerOrders = new DataRelation(
"CustomerOrders",
customers.Columns["ID"],
orders.Columns["CustomerID"]
);

companyData.Relations.Add(customerOrders);

Console.WriteLine("\nAdded relationship between Customers and Orders tables");

With relationships defined, we can navigate between related records:

csharp
// Add some order data
orders.Rows.Add(101, 1, DateTime.Now.AddDays(-5), 150.75m);
orders.Rows.Add(102, 1, DateTime.Now.AddDays(-2), 89.50m);
orders.Rows.Add(103, 2, DateTime.Now.AddDays(-7), 245.33m);

// Access related data
Console.WriteLine("\nCustomers and their orders:");
foreach (DataRow customerRow in customers.Rows)
{
Console.WriteLine($"\nCustomer: {customerRow["Name"]}");
Console.WriteLine("Orders:");

DataRow[] customerOrders = customerRow.GetChildRows("CustomerOrders");
if (customerOrders.Length > 0)
{
foreach (DataRow orderRow in customerOrders)
{
Console.WriteLine($" Order #{orderRow["OrderID"]} - " +
$"Date: {((DateTime)orderRow["OrderDate"]).ToShortDateString()}, " +
$"Amount: ${orderRow["TotalAmount"]}");
}
}
else
{
Console.WriteLine(" No orders");
}
}

Output:

Customers and their orders:

Customer: John Doe
Orders:
Order #101 - Date: [5 days ago], Amount: $150.75
Order #102 - Date: [2 days ago], Amount: $89.50

Customer: Jane Smith
Orders:
Order #103 - Date: [7 days ago], Amount: $245.33

Customer: Bob Johnson
Orders:
No orders

Filtering and Querying DataTables

Using Select Method

DataTable provides methods for querying data:

csharp
// Filter customers who joined in 2022
DataRow[] results = customers.Select("JoinDate >= #1/1/2022# AND JoinDate <= #12/31/2022#");

Console.WriteLine("\nCustomers who joined in 2022:");
foreach (DataRow row in results)
{
Console.WriteLine($"- {row["Name"]} ({((DateTime)row["JoinDate"]).ToShortDateString()})");
}

// Filter orders with amount greater than $100
DataRow[] largeOrders = orders.Select("TotalAmount > 100");

Console.WriteLine("\nOrders with amount greater than $100:");
foreach (DataRow row in largeOrders)
{
Console.WriteLine($"- Order #{row["OrderID"]} - ${row["TotalAmount"]}");
}

Computed Columns

You can add computed columns to a DataTable:

csharp
// Add a computed column to the orders table
orders.Columns.Add("Tax", typeof(decimal), "TotalAmount * 0.08");
orders.Columns.Add("GrandTotal", typeof(decimal), "TotalAmount + Tax");

Console.WriteLine("\nOrders with tax calculations:");
foreach (DataRow row in orders.Rows)
{
Console.WriteLine($"Order #{row["OrderID"]} - Subtotal: ${row["TotalAmount"]}, " +
$"Tax: ${row["Tax"]}, Total: ${row["GrandTotal"]}");
}

Output:

Orders with tax calculations:
Order #101 - Subtotal: $150.75, Tax: $12.06, Total: $162.81
Order #102 - Subtotal: $89.50, Tax: $7.16, Total: $96.66
Order #103 - Subtotal: $245.33, Tax: $19.63, Total: $264.96

Practical Example: Loading and Saving Data

Working with a Database

Let's see a practical example of loading data from a database into a DataSet and making changes:

csharp
using System;
using System.Data;
using System.Data.SqlClient;

public void LoadAndModifyData()
{
// Connection string
string connectionString = "Data Source=(local);Initial Catalog=SampleDB;Integrated Security=True";

// Create the dataset and adapter
DataSet productData = new DataSet();

// Create and configure the adapter
SqlDataAdapter adapter = new SqlDataAdapter(
"SELECT ProductID, ProductName, UnitPrice, CategoryID FROM Products",
connectionString);

// Configure commands for the adapter
SqlCommandBuilder builder = new SqlCommandBuilder(adapter);

try
{
// Fill the dataset
adapter.Fill(productData, "Products");
Console.WriteLine($"Loaded {productData.Tables["Products"].Rows.Count} products");

// Make some changes
DataTable productsTable = productData.Tables["Products"];

// Update a product price
DataRow[] productToUpdate = productsTable.Select("ProductName = 'Chai'");
if (productToUpdate.Length > 0)
{
decimal oldPrice = (decimal)productToUpdate[0]["UnitPrice"];
productToUpdate[0]["UnitPrice"] = oldPrice * 1.1m; // 10% increase
Console.WriteLine($"Updated Chai price from {oldPrice:C} to {(decimal)productToUpdate[0]["UnitPrice"]:C}");
}

// Add a new product
DataRow newProduct = productsTable.NewRow();
newProduct["ProductName"] = "New Organic Tea";
newProduct["UnitPrice"] = 25.99m;
newProduct["CategoryID"] = 1;
productsTable.Rows.Add(newProduct);
Console.WriteLine("Added new product: New Organic Tea");

// Save changes back to the database
adapter.Update(productData, "Products");
Console.WriteLine("Changes saved to database");
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
}

Saving DataSet/DataTable to XML

DataSet and DataTable can be serialized to XML, which is useful for persisting data:

csharp
// Save dataset to XML
companyData.WriteXml("CompanyData.xml");
companyData.WriteXmlSchema("CompanyData.xsd");
Console.WriteLine("\nDataSet saved to XML file");

// Load dataset from XML
DataSet loadedData = new DataSet();
loadedData.ReadXml("CompanyData.xml");
Console.WriteLine($"\nLoaded {loadedData.Tables.Count} tables from XML file");

Best Practices for Using DataSet and DataTable

  1. Use DataSets for multiple related tables, but prefer DataTable for single-table operations.
  2. Set primary keys to enable efficient lookups and relationships.
  3. Define proper column data types to prevent data conversion issues.
  4. Use constraints to enforce data integrity.
  5. Consider memory impact for large datasets - use filtering and pagination.
  6. Properly dispose of connections when working with databases.
  7. Use DataView for sorting, filtering, and searching operations.

Common Performance Tips

  1. Set proper initial capacity if you know the approximate number of rows:

    csharp
    DataTable table = new DataTable("LargeTable");
    table.MinimumCapacity = 10000;
  2. Batch processing can improve performance when adding many rows:

    csharp
    // Turn off notifications during bulk operations
    table.BeginLoadData();
    for (int i = 0; i < 10000; i++)
    {
    table.Rows.Add(i, $"Item {i}");
    }
    table.EndLoadData();
  3. Use a DataView for frequent filtering and sorting operations:

    csharp
    DataView view = new DataView(customers);
    view.Sort = "Name ASC";
    view.RowFilter = "JoinDate > #1/1/2022#";

Summary

DataSet and DataTable are powerful components in the ADO.NET framework that provide an in-memory representation of relational data. They allow you to:

  • Create and manipulate data in a disconnected manner
  • Define relationships between tables
  • Enforce data integrity through constraints
  • Query and filter data using expressions
  • Serialize data to and from XML
  • Make batch updates to a database

These components are especially useful when you need to work with multiple tables of data, perform complex data manipulation operations, or work in a disconnected environment.

Additional Resources and Exercises

Additional Resources

Exercises

  1. Create a simple inventory system with two tables: Products and Categories. Establish a relationship between them and add methods to add, update, and delete products.

  2. Build a DataTable-based contact manager that allows users to add contacts, search by name or email, and categorize contacts.

  3. Create a data processing utility that loads data from a CSV file into a DataTable, performs some analysis (like grouping and aggregating), and outputs the results.

  4. Implement a simple invoice system using DataSet with tables for Customers, Products, Orders, and OrderDetails. Include proper relationships and constraints.

  5. Create a library management system using DataTables for Books, Members, and Loans, with methods to check books in and out.

By practicing with these exercises, you'll gain a solid understanding of how to use DataSet and DataTable effectively in your C# database applications.



If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)