2013-03-05 2 views
3

У меня есть следующий запрос LINQ:Как заполнить DataTable с анонимным 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); 
    } 
} 

Update: Вот мой обновленный код:

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(); 
} 

Вот SQL-запрос я тестировал в SSMS (который должен быть эквивалент запроса 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 
+0

Это был очень удобный фрагмент кода. Мне нужно было получить данные от анонимного объекта через несколько слоев кода (не мой дизайн). Спасибо за публикацию окончательного продукта. – orgtigger

ответ

6

Если вы действительно хотите, чтобы заполнить 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(); 
+0

Отредактировано мое оригинальное сообщение, чтобы включить то, что я сейчас пытаюсь. Не могли бы вы объяснить, почему у меня это не работает? –

+0

@ChrisV: Мне кажется, вам нужно явно указать таблицу столбцов (см. Мой код), иначе это будет строка и приведет к ошибке преобразования ('По умолчанию, DataType для нового столбца является строкой') из [MSDN] (http: // msdn.microsoft.com/en-us/library/52xzw8tf.aspx) – abatishchev

+0

Нравится так? 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)); –

3

Звоните .ToList().
Результирующий List<T> также может быть привязан к DataGridView и с ним проще работать, чем с DataTable.

+0

Не все результирующие данные (столбцы) имеют один и тот же тип. Не будет ли это проблемой? –

+0

@ChrisV .: No; это строго типизированный список анонимного типа, сформированный вашими данными. – SLaks

0

Я использую FastMember для этой цели. Он использует IL instead of reflection (намного быстрее), чтобы автоматически перебирать все значения свойств и полей. Образец кода с сайта:

IEnumerable<SomeType> data = ... 
var table = new DataTable(); 
using(var reader = ObjectReader.Create(data)) 
{ 
    table.Load(reader); 
} 
Смежные вопросы