如何从对象数据源的 LINQ 查询中删除 NULL 列

本文关键字:查询 删除 NULL LINQ 对象 数据源 | 更新日期: 2023-09-27 18:31:04

正如问题所建议的那样,我想从 LINQ 查询中删除该列中的所有列,其中该列中的所有行都是空的。

目前,我正在使用 LINQ 使用所需的日期和网站筛选器运行初始查询,然后将一个 IEnumerable 对象返回到 GridView 中的对象数据源。这一切都很好用。

但是我在实现代码以删除空/NULL列时遇到困难(LINQ对我来说很新)。

这是我的工作代码,用于将 IEnumerable 返回到 ObjectDataSource:

public IEnumerable<WebApplication1.HL_Log> Select(string startDate, string endDate)
    {
        DateTime start = DateTime.Now.AddDays(-1);
        DateTime end = DateTime.Now;
        if (startDate != "01/01/1900")
        {
            DateTime.TryParse(startDate, out start);
        }
        if (endDate != "01/01/1900")
        {
            DateTime.TryParse(endDate, out end);
        }

        DataClasses1DataContext db = new DataClasses1DataContext();
        var query = from h in db.HL_Logs
                    where h.ID_Location == 45
                    && h.Time_Stamp >= start.Date
                    && h.Time_Stamp <= end.Date.AddDays(1)
                    orderby h.Time_Stamp
                    select h;
        return query;
    }

到目前为止,我已经能够将结果转换为数据表并删除空列,就像我在使用数据表的其他项目中所做的那样,使用以下方法:

//Convert to a Datatable
DataTable dt = new DataTable();
dt = LINQToDataTable(query);
//Now remove the completely NULL columns
foreach(var column in dt.Columns.Cast<DataColumn>().ToArray())
{
    if (dt.AsEnumerable().All(dr => dr.IsNull(column)))
        dt.Columns.Remove(column);
}

但是我需要先将其转换回 IEnumerable,然后才能将其返回到我的 ObjectDataSource。所以真的我的问题是,我如何将数据表转换回 IEnumerable,或者我是否对此使用了非常低效的 app,如果是这样,实现我的结果的最佳方法是什么?

到目前为止,我的总体代码:

    public IEnumerable<WebApplication1.HL_Log> Select(string startDate, string endDate)
    {
        DateTime start = DateTime.Now.AddDays(-1);
        DateTime end = DateTime.Now;
        if (startDate != "01/01/1900")
        {
            DateTime.TryParse(startDate, out start);
        }
        if (endDate != "01/01/1900")
        {
            DateTime.TryParse(endDate, out end);
        }

        DataClasses1DataContext db = new DataClasses1DataContext();
        var query = from h in db.HL_Logs
                    where h.ID_Location == 45
                    && h.Time_Stamp >= start.Date
                    && h.Time_Stamp <= end.Date.AddDays(1)
                    orderby h.Time_Stamp
                    select h;
        //Convert to a Datatable
        DataTable dt = new DataTable();
        dt = LINQToDataTable(query);         
        //Now remove the completely NULL columns
        foreach(var column in dt.Columns.Cast<DataColumn>().ToArray())
        {
            if (dt.AsEnumerable().All(dr => dr.IsNull(column)))
                dt.Columns.Remove(column);
        }
        //return ""HELP"";
    }

感谢您的帮助!!

如何从对象数据源的 LINQ 查询中删除 NULL 列

TL;DR

如果 Select 方法的使用者是 GridView DataBind() ,并且您需要一个完全动态的解决方案(例如,GridView可以绑定到 HL_Log 以外的其他类型),则最好继续返回过滤后的DataTable解决方案,因为很难针对未知类型的任意集合实现动态行隐藏。

老实说,我看不到更好、通用的方式来实现您已经在做的事情 - 需要 AFAIK 元数据,如 DataTableXmlExpandoObject

更详细

由于您的方法返回强类型实体 ( IEnumerable<WebApplication1.HL_Log> ) 的枚举,因此您不能有选择地从实体中"删除"属性或字段 - HL_Log的所有实例都将具有所有属性。我假设您当前已将AutoGenerateColumns设置为在 GridView 上true,因此需要修剪源代码中无用的列。 根据数据库列的所有值是否为空来投影不同类型的方法也很困难/乏味(例如,尝试返回 IEnumerable 并向 ExpandoObject 动态添加属性)。

此方法的替代方法是将column隐藏在GridView作为表示层关注点。但是请注意,这意味着您需要将AutoGenerateColumns设置更改为false(此处的原因),并显式检查Hl_Log的所有可见属性

var hlLogs = myObject.Select(someStartDate, someEndDate).ToList();
if (hlLogs.All(hl => hl.Property1 == null))
{
    myGridView.Columns["Property1"].Visible = false;
}
// Same for Property2, etc.

当然,这可能很快就会变得乏味。