【问题标题】:How to populate DataTable with anonymous LINQ result如何使用匿名 LINQ 结果填充 DataTable
【发布时间】:2013-02-19 06:29:55
【问题描述】:

我有以下 LINQ 查询:

var timesheets = from timesheet in entities.Timesheets
    join timesheetTask in entities.Timesheet_Task on timesheet.Id equals timesheetTask.Timesheet_Id
    join task in entities.Tasks on timesheetTask.Task_Id equals task.Id
    join project in entities.Projects on task.Project_Id equals project.Id
    join department in entities.Departments on project.Department_Id equals department.Id
    where timesheet.Employee_Id == employeeId
    select new
    {
       date = timesheet.Date,
       taskName = task.Name,
       projectName = project.Name,
       projectDesc = project.Description,
       departmentName = department.Name,
       taskEstimatedHours = task.Estimated_Hours,
       timesheetHours = timesheetTask.Hours
    };  

如何将这些结果放入 DataTable 中,然后绑定到 DataGridView 控件?

这是我目前正在做的:

    table.Columns.Add("date");
    table.Columns.Add("taskName");
    table.Columns.Add("projectName");
    table.Columns.Add("projectDesc");
    table.Columns.Add("departmentName");
    table.Columns.Add("taskEstimatedHours");
    table.Columns.Add("timesheetHours");

    foreach (var item in timesheets)
    {
        table.Rows.Add(item.date, item.taskName, item.projectName,
            item.projectDesc, item.departmentName, item.taskEstimatedHours,
            item.timesheetHours);
    }
}

更新:这是我的更新代码:

DataTable table = new DataTable();

using (PTMS_DataEntities entities = new PTMS_DataEntities())
{
    var timesheets = from timesheet in entities.Timesheets
                     join timesheetTask in entities.Timesheet_Task on timesheet.Id equals timesheetTask.Timesheet_Id
                     join task in entities.Tasks on timesheetTask.Task_Id equals task.Id
                     join project in entities.Projects on task.Project_Id equals project.Id
                     join department in entities.Departments on project.Department_Id equals department.Id
                     where timesheet.Employee_Id == employeeId
                     select new
                     {
                         date = timesheet.Date,
                         taskName = task.Name,
                         projectName = project.Name,
                         projectDesc = project.Description,
                         departmentName = department.Name,
                         taskEstimatedHours = task.Estimated_Hours,
                         timesheetHours = timesheetTask.Hours
                     };

    table.Columns.Add("date", typeof(DateTime));
    table.Columns.Add("taskName", typeof(string));
    table.Columns.Add("projectName", typeof(string));
    table.Columns.Add("projectDesc", typeof(string));
    table.Columns.Add("departmentName", typeof(string));
    table.Columns.Add("taskEstimatedHours", typeof(int));
    table.Columns.Add("timesheetHours", typeof(int));

    List<DataRow> list = new List<DataRow>();
    foreach (var item in timesheets)
    {
        //table.Rows.Add(item.date, item.taskName, item.projectName,
        //    item.projectDesc, item.departmentName, item.taskEstimatedHours,
        //    item.timesheetHours);

        var row = table.NewRow();

        row.SetField<DateTime>("date", item.date);
        row.SetField<string>("taskName", item.taskName);
        row.SetField<string>("projectName", item.projectName);
        row.SetField<string>("projectDesc", item.projectDesc);
        row.SetField<string>("departmentName", item.departmentName);
        row.SetField<int>("taskEstimatedHours", item.taskEstimatedHours);
        row.SetField<int>("timesheetHours", item.timesheetHours);

        list.Add(row);
    }

    table = list.CopyToDataTable();
}

这是我在 SSMS 中测试的 SQL 查询(应该相当于 LINQ 查询):

SELECT dbo.Department.Name, dbo.Task.Name AS Expr1, dbo.Task.Estimated_Hours, dbo.Timesheet.Date, dbo.Project.Name AS Expr2, dbo.Project.Description, 
                  dbo.Timesheet_Task.Date AS Expr3
FROM     dbo.Department INNER JOIN
                  dbo.Project ON dbo.Department.Id = dbo.Project.Department_Id INNER JOIN
                  dbo.Task ON dbo.Project.Id = dbo.Task.Project_Id INNER JOIN
                  dbo.Timesheet_Task ON dbo.Task.Id = dbo.Timesheet_Task.Task_Id INNER JOIN
                  dbo.Timesheet ON dbo.Timesheet_Task.Timesheet_Id = dbo.Timesheet.Id

【问题讨论】:

  • 这是一段非常方便的代码。我需要通过几层代码(不是我的设计)从匿名对象中获取数据。感谢您发布最终产品。

标签: c# asp.net linq data-binding ado.net


【解决方案1】:

如果你真的想填充 DataTable:

// your query
var timesheets = ...

// design table first
DataTable table = new DataTable();
table.Columns.Add(new DataColumn
    {
        ColumnName = "TaskName",
        DataType = typeof(String);
    });
...

List<DataRow> list = new List<DataRow>();
foreach (var t in timesheets)
{
    var row = table.NewRow();
    row.SetField<string>("TaskName", t.taskName); // extension method from System.Data.DataSetExtensions.dll
    ...

    list.Add(row);
}

DataTable table = list.CopyToDataTable(); // extension method too

或者更多的LINQ方式:

timesheets
    .Select(t =>
        {
            var row = table.NewRow();
            ...
            return row;
        })
    .CopyToDataTable();

或者使用相同的查询语法。实现一个方法:

static DataRow NewRow(DataRow row, string taskName, ....)
{
    ...
}

然后查询自己:

(from ...
 where ...
 select NewRow(table.NewRow(), task.Name, ...)
).CopyToDataTable();

【讨论】:

  • 编辑了我的原始帖子以包含我目前正在尝试的内容。你能解释一下为什么我的方法不起作用吗?
  • @ChrisV:我想你需要明确指定列表(参见我的代码)否则它将是字符串并导致来自MSDN的转换错误(By default, the DataType for the new column is string
  • 喜欢吗? table.Columns.Add("日期", typeof(DateTime)); table.Columns.Add("taskName", typeof(string)); table.Columns.Add("projectName", typeof(string)); table.Columns.Add("projectDesc", typeof(string)); table.Columns.Add("部门名称", typeof(string)); table.Columns.Add("taskEstimatedHours", typeof(int)); table.Columns.Add("timesheetHours", typeof(int));
  • @ChrisV:使用tilde 通常用于单行格式化。是的,looks good。它最终对你有用吗?
  • 不,仍然没有返回任何结果...这很奇怪,因为我在 SQL Server Management Studio 中运行了一个等效查询,它确实返回了结果。 ://
【解决方案2】:

致电.ToList()
生成的List&lt;T&gt; 也可以绑定到 DataGridView,并且比 DataTable 更易于使用。

【讨论】:

  • 不过,并非所有结果数据(列)都属于同一类型。这不会是个问题吗?
  • @ChrisV.:不;它是由您的数据塑造的匿名类型的强类型列表。
【解决方案3】:

我为此使用FastMember。它使用IL instead of reflection(快得多)自动迭代所有属性和字段值。来自网站的代码示例:

IEnumerable<SomeType> data = ...
var table = new DataTable();
using(var reader = ObjectReader.Create(data))
{
    table.Load(reader);
}

【讨论】:

    猜你喜欢
    • 2010-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-24
    • 2011-02-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多