How can I convert a DataTable to an IEnumerable<Dictionary<string, object>>? - linq

I'd like to convert a DataTable to an IEnumerable<> of Dictionary<string, object>. I tried the following LINQ query,
from DataRow row in ds.Tables[0].AsEnumerable()
let rowDictionary = new Dictionary<string, object>()
from DataColumn column in row.Table.Columns.Cast<DataColumn>()
select rowDictionary.Add(column.ColumnName, row[column]).ToArray();
but I get the following error:
error CS1943: An expression of type
'System.Collections.Generic.IEnumerable<System.Data.DataColumn>' is not
allowed in a subsequent from clause in a query expression with source type
'System.Data.EnumerableRowCollection<AnonymousType#1>'. Type inference
failed in the call to 'SelectMany'.
I know I can brute-force this with a loop, but it seems like something I should be able to do in LINQ. Thanks in advance for any help!

I assume that what you want is a Dictionary for each row mapping column to value:
var dt = new DataTable();
var columns = dt.Columns.Cast<DataColumn>();
dt.AsEnumerable().Select(dataRow => columns.Select(column =>
new { Column = column.ColumnName, Value = dataRow[column] })
.ToDictionary(data => data.Column, data => data.Value));

Here is a way I do it in the Linq format
var registerdataVerify = (from o in dt.AsEnumerable()
select new
{
DataDef =o["shortName"].ToString(),
Value = Convert.ToInt32(o["valueDec"])
}).ToDictionary(n => n.DataDef, n => n.Value);

Why not something simpler since you have linq?
var dt = new DataTable();
var columnIndex = 0;
var columnName = "UserID";
var Dict = dt.AsEnumerable().ToDictionary( _
row => row(columnName), _
row => row(columnIndex));
It becomes even easier if you're working with strongly-typed datasets:
var dt = new dsData.UsersDataTable();
var Dict = dt.ToDictionary(dr => dr.UserName, dr => dr.UserID);

Related

What's the equivalent of GROUP INTO in Linq extension method?

This is how I'm filtering and grouping transTasks.
var transTasks = from t in taskData
where t.RangeName == rName
group t by t.CultureID into g
select new { language = g.Key, tasks = g };
Now I've a new requirement. Depending on the conditions, I'may filter by RangeName or by TaskOrderId.
That's why I've transformed the above Linq code to the following;
var transTasks = taskData
.Where(predicate)
.GroupBy(???)
.Select(???);
I've researched but I can't still find the equivalent of group into for the extension method. I need to group those transTasks because there is a loop inside another loop.
Thanks for helping
GroupBy is the equivalent , and it seems you have figured it out, your query in Method Syntax would be:
var transTrasks = taskData.Where(t => t.RangeName == rName)
.GroupBy(t => t.CultureID)
.Select(g => new { language = g.Key, tasks = g });
As a side note, Any LINQ query in query expression compiles to Method Syntax.
var transTasks = taskData
.Where(predicate)
.GroupBy(t => t.CultureID)
.Select(g => new { language = g.Key, tasks = g });

Linq CopyToDataTable using extension methods

Hello I'm trying to copy the following linq results to a datatable. The only examples I see of copytodatatable is using the query format, and not the extension methods. Wondering if anyone knows how to use it with the extension methods (I've tried casting the results to IEnumerable datarow but it didn't work).
DataTable dtItemPricingBreakDown =
SiteHelper.getItemPricingBreakDown(CustomerId,
PriceBookID,
deliveryZip,
dtItems,
db,
departmentId);
dtItemPricingBreakDown.AsEnumerable()
.GroupBy(i => new {
sku = i.Field<string>("sku"),
deptid = i.Field<int>("department_id")
})
.Select(group => new
{
sku = group.Key.sku,
deptid = group.Key.deptid,
cnt = group.Count()
});
Update
Better late than never, sorry for the delay in response. My actual issue appears to be for both the query syntax and the extension methods.
Something like this works according to msdn
(http://msdn.microsoft.com/en-us/library/bb386921(v=vs.110).aspx):
// Fill the DataSet.
DataSet ds = new DataSet();
ds.Locale = CultureInfo.InvariantCulture;
FillDataSet(ds);
DataTable orders = ds.Tables["SalesOrderHeader"];
DataTable details = ds.Tables["SalesOrderDetail"];
var query =
from order in orders.AsEnumerable()
join detail in details.AsEnumerable() on order.Field<int>("SalesOrderID") equals detail.Field<int>("SalesOrderID")
where order.Field<bool>("OnlineOrderFlag") == true
&& order.Field<DateTime>("OrderDate").Month == 8
select new
{
SalesOrderID = order.Field<int>("SalesOrderID"),
SalesOrderDetailID = detail.Field<int>("SalesOrderDetailID"),
OrderDate = order.Field<DateTime>("OrderDate"),
ProductID = detail.Field<int>("ProductID")
};
DataTable orderTable = query.CopyToDataTable();
But when I try this...
var query = from exx in dtItemPricingBreakDown.AsEnumerable()
group exx by new { sku = exx.Field<string>("sku"), companyId = exx.Field<int>("department_id") } into grp
select new { sku = grp.Key.sku, DepartmentID = grp.Key.companyId, Cnt = grp.Count() };
DataTable dt3 = query.CopyToDataTable();
I get this exception: "No implicit reference conversion from anonymoustype1 to system.data.datarow". I've tried doing what they did with the dataset in the msdn example as well and I still get the error. Extension method wise I was trying something like this...and still got the same exception.
DataTable dt3 = dtItemPricingBreakDown.AsEnumerable().GroupBy(i => new
{
sku = i.Field<string>("sku"),
deptid = i.Field<int>("department_id")
}).Select(group => new
{
sku = group.Key.sku,
DepartmentID = group.Key.deptid,
cnt = group.Count()
}).Cast<DataRow>().CopyToDataTable();

Select top N with record from DataTable with some sorting using Linq

I have created a DataTable. I have populated the rows of the DataTable after some operations.
I am very new to Linq I want to Get the Top "N" Records from the DataTable implementing also some paging.
Let dataTable is the DataTable having some data.
I am need something like this
var Query = from d in dataTable
Order by columnName
skip( some records pageSize * pageNumber)
Select top N from dataTable
The column Name, Page size ,pageNumber and the N will passed as arguments
Try this:
var query = dataTable.AsEnumerable()
.OrderBy(c => c.columnName)
.Select(r => new {...})
.Skip(10)
.Take(5)
Try this,
int numberOfObjectsPerPage = 20;
var queryResultPage = dataTable.OrderBy(c => c.columnName).Select(r => r).Skip(numberOfObjectsPerPage * pageNumber).Take(numberOfObjectsPerPage);
Try this
var Query = dataTable.Select(o=>o).OrderBy(o=>o.columnName).Skip(pageSize * pageNumber).Take(N);
EDIT
For pass column name you should to add this code
public static IQueryable<T> OrderByField<T>(this IQueryable<T> q, string SortField, bool Ascending)
{
var param = Expression.Parameter(typeof(T), "p");
var prop = Expression.Property(param, SortField);
var exp = Expression.Lambda(prop, param);
string method = Ascending ? "OrderBy" : "OrderByDescending";
Type[] types = new Type[] { q.ElementType, exp.Body.Type };
var mce = Expression.Call(typeof(Queryable), method, types, q.Expression, exp);
return q.Provider.CreateQuery<T>(mce);
}
And then you could call it in this way
var values = dataTable.OrderByField("columnName");

Trim whitespace from DataTable cells with Linq

This piece of code works to trim all spaces in each datacell of each datarow.
How can I get this code:
var dataRows = dataTable.AsEnumerable();
foreach (var row in dataRows)
{
var cellList = row.ItemArray.ToList();
row.ItemArray = cellList.Select(x => x.ToString().Trim()).ToArray();
}
into one line of code so I don't have to loop through each row? Something like this but it doesn't work:
dataTable.AsEnumerable().Select(y => y.ItemArray.ToList()).Select(x => x.ToString().Trim());
If you love LINQish stype:
dataTable.AsEnumerable().ToList()
.ForEach(row =>
{
var cellList = row.ItemArray.ToList();
row.ItemArray = cellList.Select(x => x.ToString().Trim()).ToArray();
});
With linq you can't change item values finally you should run for loop (or foreach) to change fields value.
for example
var iq = obj from dataTable.asEnumerable() select new{
PersonName = a.Field<string>("PersonName"),
PersonID = a.Field<decimal>("PersonID"),
ParticipantString = a.Field<string>("DisplayString"),
PersonUserName = d.Field<string>("UserName")
}

Linq to CSV select by column

If I have the following (sample) text file;
year,2008,2009,2010
income,1000,1500,2000
dividends,100,200,300
net profit,1100,1700,2300
expenses,500,600,500
profit,600,1100,1800
Is there a way in Linq that I can select the expenses for 2010 only?
So far I have the following which gets me all the data;
var data = File.ReadAllLines(fileName)
.Select(
l => {
var split = l.CsvSplit();
return split;
}
);
foreach (var item in data)
Console.WriteLine("{0}: ${1}", item[0], item[1]);
If you know it's always the 3rd value column, then
// the expenses row
var query = data.Single(d => d[0] == "expenses");
// the third column
return query[3];
and if you don't, then
var columnNumber = Array.IndexOf(data.First(), "2010");
return query[columnNumber];
See LINQtoCSV, its a library that does all this for you. I've used it, and it works like a charm.
http://www.codeproject.com/KB/linq/LINQtoCSV.aspx

Resources