从DataTable获取单个值的最佳方法是什么?

时间:2010-04-14 12:47:37

标签: c# .net datatable data-access

我有许多包含这样的表的静态类:

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"];
    }
}

是否有更好的方法来编写Data1或Data2方法,这些方法从与给定id匹配的单行返回单个值?

更新#1:

我创建了一个看起来很不错的扩展方法:

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.");
    }
}

我的Data1方法变为:

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

和Data2成为:

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

感谢您的所有回复,尤其感谢Anthony Pegram,他提供了非常好的单行LINQ&amp; Lambda代码。

2 个答案:

答案 0 :(得分:3)

您是否考虑过使用Linq (to DataSets)?使用Linq表达式,您根本不需要那些Data1和Data2函数,因为查找和过滤可能只发生在一行代码中。

添加了示例:

在这里从臀部拍摄,所以请带上一粒盐(不在IDE附近):

DataTable itemTbl = GetItemTable().AsEnumerable();

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

这是两行代码,但你可以轻松地包含Enumerable的获取。

答案 1 :(得分:0)

我对你的建筑有点怀疑,但没关系。如果你想要一个函数来返回它将以某种方式得到的数据表的第一行的第一行,并且你想要它强类型,我认为下面的函数将是一个改进。它允许您只有一个功能,可以重复使用不同类型。要使用它,您将拥有如下代码行:

int intValue = TableFoo.FirstValueOrDefault<int32>(7);
decimal decValue = TableFoo.FirstValueOrDefault<decimal>(7);

如果您愿意的话:

string strValue = TableFoo.FirstValueOrDefault<string>(7);
int? nintValue = TableFoo.FirstValueOrDefault<int?>(7);

该函数处理您通常提供的任何类型,字符串,其他值类型,可空类型,引用类型。如果该字段为null,则该函数返回该类型的“默认”值(“”表示字符串)。如果它绝对无法进行转换,因为您要求进行不可能的转换,它将引发错误。我已经把它作为datarow类型的扩展方法(称为ValueOrDefault),这个吸盘非常方便

我根据您的情况调整了我的数据工具扩展方法。我在VB商店,我没有时间用C#重写整个东西,但你可以很容易地做到这一点。

Public Shared Function FirstValueOrDefault(Of T) (ByVal Int ID) As T
    Dim r as datarow = ItemTable.Select("Id = " + id.ToString());
    If r.IsNull(0) Then
        If GetType(T) Is GetType(String) Then
            Return CType(CType("", Object), T)
        Else
            Return Nothing
        End If
    Else
        Try
            Return r.Field(Of T)(0)
        Catch ex As Exception
            Return CType(r.Item(0), T)
        End Try
    End If
End Function