从数据表获取单个值的最佳方法?

发布于 2024-08-29 12:27:25 字数 2281 浏览 6 评论 0原文

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

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&拉姆达代码。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

趁微风不噪 2024-09-05 12:27:25

您是否考虑过使用Linq(到数据集)?使用 Linq 表达式,您根本不需要这些 Data1 和 Data2 函数,因为查找和过滤可以在一行代码中进行。

添加示例:

这里是从臀部出发,所以请持保留态度(不要靠近 IDE:)

DataTable itemTbl = GetItemTable().AsEnumerable();

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

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

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.

仙气飘飘 2024-09-05 12:27:25

我对你的架构有点怀疑,但没关系。如果您想要一个返回数据表第一行的第一个值的函数,并且您希望它是强类型的,我认为下面的函数将是一个改进。它将允许您只有一个函数,可重复用于不同类型。要使用它,您将拥有如下代码行:

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

如果您愿意的话:

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

该函数处理您通常给它的任何类型,字符串,其他值类型,可空类型,引用类型。如果该字段为空,则该函数返回该类型的“默认”值(“”表示字符串)。如果它绝对无法进行转换,因为您要求进行不可能的转换,它将抛出错误。我已将其作为数据行类型的扩展方法(称为 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

I'm a little suspicious of your architecture, but never mind that. If you want a function that returns the first value of the first row of a datatable that it will get somehow, and you want it strongly typed, I think the function below will be an improvement. It would allow you to have just one function, reusable for different types. To use it you would have lines of code like:

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

and if you feel like it:

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

The function handles any type you generically give it, strings, other value types, nullable types, reference types. If the field is null, the function returns the "default" value for that type ("" for string). If it absolutely can't do the conversion, because you asked for an impossible conversion, it will throw an error. I've made it an extension method on the datarow type (called ValueOrDefault), and this sucker is really handy.

I adapted this data-tool extension method of mine for your situation. I'm in a VB shop, and I just don't have time to re-write the whole thing in C#, but you could do that easily enough.

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文