Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best way to get a single value from a DataTable?

I have a number of static classes that contain tables like this:

using System;
using System.Data;
using System.Globalization;

public static class TableFoo
{
    private static readonly DataTable ItemTable;

    static TableFoo()
    {
        ItemTable = new DataTable("TableFoo") { Locale = CultureInfo.InvariantCulture };
        ItemTable.Columns.Add("Id", typeof(int));
        ItemTable.Columns["Id"].Unique = true;
        ItemTable.Columns.Add("Description", typeof(string));
        ItemTable.Columns.Add("Data1", typeof(int));
        ItemTable.Columns.Add("Data2", typeof(double));

        ItemTable.Rows.Add(0, "Item 1", 1, 1.0);
        ItemTable.Rows.Add(1, "Item 2", 1, 1.0);
        ItemTable.Rows.Add(2, "Item 3", 2, 0.75);
        ItemTable.Rows.Add(3, "Item 4", 4, 0.25);
        ItemTable.Rows.Add(4, "Item 5", 1, 1.0);
    }

    public static DataTable GetItemTable()
    {
        return ItemTable;
    }

    public static int Data1(int id)
    {
        DataRow[] dr = ItemTable.Select("Id = " + id);
        if (dr.Length == 0)
        {
            throw new ArgumentOutOfRangeException("id", "Out of range.");
        }

        return (int)dr[0]["Data1"];
    }

    public static double Data2(int id)
    {
        DataRow[] dr = ItemTable.Select("Id = " + id);
        if (dr.Length == 0)
        {
            throw new ArgumentOutOfRangeException("id", "Out of range.");
        }

        return (double)dr[0]["Data2"];
    }
}

Is there a better way of writing the Data1 or Data2 methods that return a single value from a single row that matches the given id?

Update #1:

I have created an extension method that seems quite nice:

public static T FirstValue<T>(this DataTable datatable, int id, string fieldName)
{
    try
    {
        return datatable.Rows.OfType<DataRow>().Where(row => (int)row["Id"] == id).Select(row => (T)row[fieldName]).First();
    }
    catch
    {
        throw new ArgumentOutOfRangeException("id", "Out of range.");
    }
}

My Data1 method then becomes:

public static int Data1(int id)
{
    return ItemTable.FirstValue<int>(id, "Data1");
}

and Data2 becomes:

public static double Data2(int id)
{
    return ItemTable.FirstValue<double>(id, "Data2");
}

Thanks to all your responses but especially to Anthony Pegram who gave the very nice single line of LINQ & Lambda code.

like image 529
Piers Myers Avatar asked Apr 14 '10 12:04

Piers Myers


1 Answers

Have you considered using Linq (to DataSets)? With Linq expressions you wouldn't need those Data1 and Data2 functions at all since the lookup and filtering could happen in a single line of code.

Example added:

Shooting from the hip here, so please take it with a grain of salt (not near an IDE:)

DataTable itemTbl = GetItemTable().AsEnumerable();

double dt1 = ((From t In itemTbl Where t.Id = <your_id> Select t).First())["Data1"];

That's two lines of code but you could easily wrap the getting of the Enumerable.

like image 127
Paul Sasik Avatar answered Sep 22 '22 13:09

Paul Sasik