Save linq query as data table - c#

In c# MVC, I need to get the following "result" (var) in the data table.
var allCompanies = objentity.ExecuteFunction<SearchAvailEmployees_Result>("SearchAvailEmployees", lstParam.ToArray())
.ToList();
var result = from c in allCompanies select new[] {
c.LastName,
c.FirstName,
c.Phone,
c.City,
c.PositionApplied,
c.Status,
Convert.ToString(c.CallDate.Value.ToShortDateString()),
Convert.ToString(c.CellOrPager),
c.Gender
};
I tried the following code but it won't works. It gives the error as
"Cannot implicitly convert type 'System.Collections.Generic.IEnumerable' to 'System.Collections.Generic.IEnumerable'. An explicit conversion exists (are you missing a cast?)"
IEnumerable<DataRow> query = from c in allCompanies select new[] {
c.LastName,
c.FirstName,
c.Phone,
c.City,
c.PositionApplied,
c.Status,
Convert.ToString(c.CallDate.Value.ToShortDateString()),
Convert.ToString(c.CellOrPager),
c.Gender
};
DataTable boundTable = query.CopyToDataTable<DataRow>();
Any alternate solution to save the linq query result in data table?

This is how I do it:
First I declare a new DataTable and add columns, in this :
DataTable dt = new DataTable();
dt.Columns.Add("FirstName");
dt.Columns.Add("LastName");
DataRow row = null;
Now I execute the desired query:
var query = from c in allCompanies select { c.LastName, c.FirstName};
Now I simply iterate through the query and fill a DataTable:
foreach (var rowObj in query)
{
row = dt.NewRow();
dt.Rows.Add(rowObj.FirstName, rowObj.LastName);
}
return dt;
Still in my queries I am using 'join'-statements.

First, create DataTable with correct schema:
var dataTable = new DataTable();
dataTable.Columns.Add("LastName", typeof (string));
dataTable.Columns.Add("FirstName", typeof(string));
// Add more columns
Second, select array of value object:
var result = allCompanies.Select(c => new object[] {
c.LastName,
c.FirstName,
c.Phone,
c.City,
c.PositionApplied,
c.Status,
Convert.ToString(c.CallDate.Value.ToShortDateString()),
Convert.ToString(c.CellOrPager),
c.Gender
}).ToList();
Third, loop to create new Row from DataTable and assign value to new Row:
result.Foreach(array => {
var row = dataTable.NewRow();
row.ItemArray = array;
dataTable.Rows.Add(row);
});

You should remove [] after new, it to be like
var result = from c in allCompanies
select new { c.LastName, c.FirstName, c.Phone, c.City,
c.PositionApplied, c.Status,
CallDate = Convert.ToString(c.CallDate.Value.ToShortDateString()),
CellOrPager = Convert.ToString(c.CellOrPager), c.Gender };
Create DataTable here
var dataTable = new DataTable();
dataTable.Columns.AddRange( new DataColumn[]{
new DataColumn("LastName" , typeof(string)),
new DataColumn("FirstName" , typeof(string)),
new DataColumn("Phone" , typeof(string)),
new DataColumn("City" , typeof(string)),
new DataColumn("PositionApplied" , typeof(string)),
new DataColumn("Status" , typeof(string)),
new DataColumn("CallDate" , typeof(string)),
new DataColumn("CellOrPager" , typeof(string)),
new DataColumn("Gender" , typeof(string))
});
Fill DataTable using this result
result.ToList().ForEach(x=>{
var row = dataTable.NewRow();
row.["LastName"] = x.LastName;
row.["FirstName"] = x.FirstName;
row.["Phone"] = x.Phone;
row.["City"] = x.City;
row.["PositionApplied"] = x.PositionApplied;
row.["Status"] = x.Status;
row.["CallDate"] = x.CallDate;
row.["CellOrPager"] = x.CellOrPager;
row.["Gender"] = x.Gender;
dataTable.Rows.Add(row);
});

Related

Fastest way to create DataTable from List without for loop

We have a huge list (say 100,000) which needs to be converted to DataTable for SqlBulkcopy.
Can you guide what could be the fastest way to do this without using for loop?
For now we are doing it like - in below code listDos is object list
using (var dataTable = new DataTable(dataTableName))
{
dataTable.Locale = CultureInfo.CurrentCulture;
var columns = new[]
{
new DataColumn("Id", typeof(int)),
new DataColumn("FkId", typeof(int)),
new DataColumn("Status", typeof(string)),
new DataColumn("RecordFrom", typeof(DateTime))
};
dataTable.Columns.AddRange(columns);
foreach (ObjectDo listDo in listDos)
{
var row = dataTable.NewRow();
if (rebuildDo.Id != null) row["Id"] = rebuildDo.Id;
if (rebuildDo.FkId!= null) row["FkId"] = rebuildDo.FkId;
row["Status"] = rebuildDo.Status;
row["RecordFrom"] = rebuildDo.RecordFrom;
dataTable.Rows.Add(row);
}
return dataTable;
}
The fastest way would be: not to.
SqlBulkCopy can take an IDataReader. "FastMember" (on NuGet) can expose a List<T> as an IDataReader:
List<ObjectDo> listDos = ...
using(var bcp = new SqlBulkCopy(connection))
using(var reader = ObjectReader.Create(listDos,
"Id", "FkId", "Status", "RecordFrom"))
{
bcp.DestinationTableName = "SomeTable";
bcp.WriteToServer(reader);
}
This is now a direct reader over the list: no duplication of all the contents.

Need to merge 2 rows in dynamic table

Hi I have created dynamic table as below and in that I have 2 rows with same id
How should I merge them.
DataTable dt = new DataTable();
dt = (DataTable)Session["AddtoCart"];
DataRow dr1 = dt.NewRow();
foreach (var key in collection.AllKeys)
{
dr1["Description"] = collection["hdDescription"];
dr1["Title"] = collection["hdTitle"];
dr1["ActualQuantity"] = collection["hdactualquantity"];
dr1["PropertyId"] = collection["hdPropertyId"];
dr1["Quantity"] = collection["Quantity"];
TempData["AddedtoCart"] = ConfigurationManager.AppSettings["AddtoCart"].ToString();
}
dt.Rows.Add(dr1);
My added rows are as
Propertyid, Quantity, ActualQuantity
1 5 10
1 2 10
2 3 20
2 4 20
Th result i needed is as
Propertyid, Quantity, ActualQuantity
1 7 10
2 7 20
Update: i have tried this answer:
var query = dt.AsEnumerable()
.GroupBy(row => row.Field<int>("PropertyId"))// issue over this line
.Select(grp => new
{
PropertyId = grp.Key,
Quantity = grp.Sum(row => row.Field<int>("Quantity")),
ActualQuantity = grp.First().Field<int>("ActualQuantity"),
Title = grp.First().Field<int>("Title"),
Description = grp.First().Field<int>("Description")
});
var SumByIdTable = dt.Clone();
foreach (var x in query)
SumByIdTable.Rows.Add(x.PropertyId, x.Quantity, x.ActualQuantity,x.Title, x.Description);
Session["AddtoCart"] = SumByIdTable;
but I am getting issue as Specified cast is not valid. on .GroupBy(row => row.Field("PropertyId"))
Update 2: I have tried below code but i am getting issue
DataTable dt = new DataTable();
dt.Columns.Add("PropertyId", typeof(int));
dt.Columns.Add("Quantity", typeof(int));
dt.Columns.Add("Description", Type.GetType("System.String"));
dt.Columns.Add("Title", Type.GetType("System.String"));
dt.Columns.Add("ActualQuantity", typeof(int));
DataRow dr1 = dt.NewRow();
foreach (var key in collection.AllKeys)
{
dr1["Description"] = collection["hdDescription"];
dr1["Title"] = collection["hdTitle"];
dr1["ActualQuantity"] = Convert.ToInt32(collection["hdactualquantity"]);
dr1["PropertyId"] = Convert.ToInt32(collection["hdPropertyId"]);
dr1["Quantity"] = Convert.ToInt32(collection["Quantity"]);
TempData["AddedtoCart"] = ConfigurationManager.AppSettings["AddtoCart"].ToString();
}
dt.Rows.Add(dr1);
var query = dt.AsEnumerable()
.GroupBy(row => row.Field<int>("PropertyId"))
.Select(grp => new
{
PropertyId = grp.Key,
Quantity = grp.Sum(row => row.Field<int>("Quantity")),
ActualQuantity = grp.First().Field<int>("ActualQuantity"),
Title = grp.First().Field<string>("Title"),
Description = grp.First().Field<string>("Description")
});
var SumByIdTable = dt.Clone();
foreach (var x in query)
SumByIdTable.Rows.Add(x.PropertyId, x.Quantity, x.ActualQuantity,x.Title, x.Description);
Session["AddtoCart"] = SumByIdTable;
but I am getting issue in
SumByIdTable.Rows.Add(x.PropertyId, x.Quantity, x.ActualQuantity,x.Title, x.Description);
Input string was not in a correct format.
Resolved Update 3: I have tried below code and is working
DataTable dt = new DataTable();
dt.Columns.Add("PropertyId", typeof(int));
dt.Columns.Add("Quantity", typeof(int));
dt.Columns.Add("Description", Type.GetType("System.String"));
dt.Columns.Add("Title", Type.GetType("System.String"));
dt.Columns.Add("ActualQuantity", typeof(int));
DataRow dr1 = dt.NewRow();
foreach (var key in collection.AllKeys)
{
dr1["Description"] = collection["hdDescription"];
dr1["Title"] = collection["hdTitle"];
dr1["ActualQuantity"] = Convert.ToInt32(collection["hdactualquantity"]);
dr1["PropertyId"] = Convert.ToInt32(collection["hdPropertyId"]);
dr1["Quantity"] = Convert.ToInt32(collection["Quantity"]);
TempData["AddedtoCart"] = ConfigurationManager.AppSettings["AddtoCart"].ToString();
}
dt.Rows.Add(dr1);
var query = dt.AsEnumerable()
.GroupBy(row => row.Field<int>("PropertyId"))
.Select(grp => new
{
PropertyId = grp.Key,
Quantity = grp.Sum(row => row.Field<int>("Quantity")),
ActualQuantity = grp.First().Field<int>("ActualQuantity"),
Title = grp.First().Field<string>("Title"),
Description = grp.First().Field<string>("Description")
});
var SumByIdTable = dt.Clone();
foreach (var x in query)
SumByIdTable.Rows.Add(Convert.ToInt32(x.PropertyId), Convert.ToInt32(x.Quantity), x.Description, x.Title, Convert.ToInt32(x.ActualQuantity));
Session["AddtoCart"] = SumByIdTable;
changes was I have to add the value in SumByIdTable as clone set in dt
You can use LINQ (-to-DataTable):
var query = dt.AsEnumerable()
.GroupBy(row => row.Field<int>("Propertyid"))
.Select(grp => new {
Propertyid = grp.Key,
Quantity = grp.Sum(row => row.Field<int>("Quantity")),
ActualQuantity = grp.First().Field<int>("ActualQuantity")
});
var SumByIdTable = dt.Clone();
foreach(var x in query)
SumByIdTable.Rows.Add(x.Propertyid, x.Quantity, x.ActualQuantity);

Compare 2 excel columns for similarity and return the matched values in datatable using openxml

I have to compare 2 columns present in different excel sheets and return the matched values using openxml(C#).Both the columns have some account Numbers.
I am able to get the unmatched values using the below code.But I need the matched values.Please suggest.
public static DataTable DocomparisionCOA_ACCT(DataSet dtPrimaryFile, DataSet dtValidationFile)
{
DataTable COA_BU = new DataTable();
DataTable validationsheet1 = dtValidationFile.Tables["COA"];
DataTable primarydatafile = dtPrimaryFile.Tables["JE"];
var qry1 = validationsheet1.AsEnumerable().Select(a => new { bu = a["Acct"].ToString() });
var qry2 = primarydatafile.AsEnumerable().Select(b => new { bu = b["ACCT"].ToString() });
var exceptAB = qry1.Except(qry2);
COA_BU = (from a in validationsheet1.AsEnumerable()
join ab in exceptAB on a["ACCT"].ToString() equals ab.bu
select a).CopyToDataTable();
DataColumn AcctColumn = COA_BU.Columns["Accts"];
return COA_BU;
}

SqlBulkCopy.WriteToServer doesn't works

Sorry for asking, but I haven't solved my question by reading another situation like I have.
I have an array with longs and I should insert it into a database, that has only 2 fields: OGRN - bigint, data field, Id - int, identity field. I'm creating a DataTable like this
private static DataTable CreateDataTable()
{
var result = new DataTable();
var ogrn = new DataColumn("Ogrn") {DataType = typeof (long), ColumnName = "Ogrn"};
result.Columns.Add(ogrn);
var id = new DataColumn("Id") { DataType = typeof(int), ColumnName = "Id", AutoIncrement = true };
result.Columns.Add(id);
result.PrimaryKey = new[] { id };
return result;
}
after i'm doing this:
var dt = CreateDataTable();
foreach (long ogrn in ogrns)
{
var row = dt.NewRow();
row["Ogrn"] = ogrn;
dt.AcceptChanges();
}
using (var sqlBulkCopy = new SqlBulkCopy(ConnectionString))
{
sqlBulkCopy.DestinationTableName = "dbo.ULs";
sqlBulkCopy.ColumnMappings.Add("Ogrn", "Ogrn");
sqlBulkCopy.ColumnMappings.Add("Id", "Id");
sqlBulkCopy.WriteToServer(dt);
}
So why doesn't it work? Am I missing something important.
Add the new row to the Table!. That is not something that is automagically done when you call NewRow();
var dt = CreateDataTable();
foreach (long ogrn in ogrns)
{
var row = dt.NewRow();
row["Ogrn"] = ogrn.Ogrn;
dt.Rows.Add(row); // ADD the new row to the table!
}
dt.AcceptChanges();

How to populate DataTable with anonymous LINQ result

I have the following LINQ query:
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
};
How can I put these results into a DataTable which I can then bind to a DataGridView control?
This is what I'm currently doing:
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: Here is my updated code:
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();
}
Here is the SQL query I tested in SSMS (which should be the equivalent of the LINQ query):
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
If you really want to populate 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
Or more LINQ way:
timesheets
.Select(t =>
{
var row = table.NewRow();
...
return row;
})
.CopyToDataTable();
Or in same query syntax. Implement a method:
static DataRow NewRow(DataRow row, string taskName, ....)
{
...
}
Then query itself:
(from ...
where ...
select NewRow(table.NewRow(), task.Name, ...)
).CopyToDataTable();
Call .ToList().
The resulting List<T> can also be bound to a DataGridView, and is easier to work with than a DataTable.
I'm using FastMember for this purpose. It uses IL instead of reflection (much faster) to iterate over all of the property and field values automatically. Code sample from the site:
IEnumerable<SomeType> data = ...
var table = new DataTable();
using(var reader = ObjectReader.Create(data))
{
table.Load(reader);
}

Categories

Resources