How can I use LINQ to select all the Company Name and Company ID from all the rows? I need something like this pseudo-code:
var typedQry = from b in allData.AsEnumerable()
where b.GetHeader("xxx") == "08/10/09 to 08/26/09"
select CompanyName, CompanyID, ...
The code below selects only one Company Name. Instead, I want Company Name from all the rows:
var typedQry3 = from b in allData.AsEnumerable()
select new { compname0 = b._rows[0][5]};
The data in _rows are Company Name (e.g., allData[0]._rows[0][5], allData[0]._rows[1][5],....), Company ID, and so forth.
However, Company Name, Company ID, and etc. are not defined in the DataProperty class. Their values are inserted into _rows from data files.
Any help is appreciated. Below is some code to help you understand my question.
List<DataProperty> allData = new List<DataProperty>();
The DataProperty class consists of
private readonly Dictionary<string, string> _headers = new Dictionary<string, string>();
private readonly List<string[]> _rows = new List<string[]>();
and these methods (among others):
public string[] GetDataRow(int rowNumber){return _rows[rowNumber];}
public void AddDataRow(string[] row){_rows.Add(row);}
according to your comment, if you need to the sum for each company you can try this:
var RowList1 = allData.SelectMany(u => u._rows.Select(t => new
{
CompanyName = t[5],
Amount = Convert.ToInt64(t[1]) + Convert.ToInt64(t[2])
}))
.Where(u => u.CompanyName == "XXX")
.OrderBy(u => u.CompanyName)
.ToList();
and if you need to sum of the all companies, you can try this:
var SumAmount = allData.SelectMany(u => u._rows.Select(t => new
{
CompanyName = t[5],
Amount = Convert.ToInt64(t[1]) + Convert.ToInt64(t[2])
}))
.Where(u => u.CompanyName == "XXX")
.DefaultIfEmpty()
.Sum(u => u.Amount);
you can write your own and customized query using these
you can use this to get all company names:
var AllCompanyNames = allData.SelectMany(u => u._rows.Select(t => t[5])).ToList();
and this, to get more property:
var Rows = allData.SelectMany(u =>
u._rows.Select(t => new
{
CompanyName = t[5],
Other1 = t[1],
Other2 = t[2]
}))
.ToList();
and this, if you need to check any condition:
var FilteredRows = allData.SelectMany(u =>
u._rows.Select(t => new
{
CompanyName = t[5],
Other1 = t[1],
Other2 = t[2]
}))
.Where(u => u.CompanyName == "XXX")
.ToList();
At first you can receive rows and then iterate through them.
This example may help you
var rows = (from DataRow dRow in dTable.Rows
select new {col1=dRow["dataColumn1"],col2=dRow["dataColumn2"]});
foreach (var row in distinctRows)
{
var value1=row.col1.ToString();
var value2=row.col2.ToString();
}
Related
I'm reading a CSV file splitting it into cols, then grouping into a new class.
It looks clunky just wondering is there is a more simple method for instance like not selecting them into the class first:
EDIT: so to clarify I'm trying to get the TimesheetHours grouped by all the other columns.
var rowList = csvFile.Rows.Select(row => row.Split(','))
.Select(cols => new UtilisationRow {
UploadId = savedUpload.Id,
FullName = cols[0],
TimesheetWorkDateMonthYear = Convert.ToDateTime(cols[1]),
TimesheetTaskJobnumber = cols[2],
TimesheetWorktype = cols[3],
TimesheetHours = Convert.ToDouble(cols[4]),
TimesheetOverhead = cols[5]
})
.GroupBy(d => new {
d.FullName,
d.TimesheetWorkDateMonthYear,
d.TimesheetTaskJobnumber,
d.TimesheetWorktype,
d.TimesheetOverhead
})
.Select(g => new UtilisationRow {
FullName = g.First().FullName,
TimesheetWorkDateMonthYear = g.First().TimesheetWorkDateMonthYear,
TimesheetTaskJobnumber = g.First().TimesheetTaskJobnumber,
TimesheetWorktype = g.First().TimesheetWorktype,
TimesheetHours = g.Sum(s => s.TimesheetHours),
TimesheetOverhead = g.First().TimesheetOverhead
})
.ToList();
Many thanks,
Lee.
The two problems in your code are that you call First() repeatedly on a group, while you should retrieve that same data from group's key, and that you are using UtilisationRow in the first Select, which should use an anonymous type instead:
var rowList = csvFile.Rows.Select(row => row.Split(','))
.Select(cols => new {
UploadId = savedUpload.Id,
FullName = cols[0],
TimesheetWorkDateMonthYear = Convert.ToDateTime(cols[1]),
TimesheetTaskJobnumber = cols[2],
TimesheetWorktype = cols[3],
TimesheetHours = Convert.ToDouble(cols[4]),
TimesheetOverhead = cols[5]
})
.GroupBy(d => new {
d.FullName,
d.TimesheetWorkDateMonthYear,
d.TimesheetTaskJobnumber,
d.TimesheetWorktype,
d.TimesheetOverhead
})
.Select(g => new UtilisationRow {
FullName = g.Key.FullName,
TimesheetWorkDateMonthYear = g.Key.TimesheetWorkDateMonthYear,
TimesheetTaskJobnumber = g.Key.TimesheetTaskJobnumber,
TimesheetWorktype = g.Key.TimesheetWorktype,
TimesheetHours = g.Sum(s => s.TimesheetHours),
TimesheetOverhead = g.Key.TimesheetOverhead
})
.ToList();
Now the "pipeline" of your method looks pretty clean:
The first Select does the initial parsing into a temporary record
GroupBy bundles matching records into a group
The final Select produces records of the required type.
I have this DataSet of Visitors that has a column VisitorGroupID that can either be NULL or have a value that refers to another table thats called VisitorGroups. I want to read the GroupName (column belongs in VisitorGroups) for the specific Visitor in my page, how should my query look like?
This is what I have done for now, but this returns all groups existing which is wrong.
C#:
private DataSet _groups;
var results = _groups.Tables[0].AsEnumerable()
.GroupBy(x => x["GroupName"]).Select(g => g.First())
.Where(x => !string.IsNullOrEmpty(x["GroupName"].ToString()))
.CopyToDataTable();
An example to select the group of the user with the id==1:
_groups = new DataSet();
_groups.Tables.Add(new DataTable("users"));
_groups.Tables.Add(new DataTable("groups"));
_groups.Tables[0].Columns.Add("id_user", typeof(int));
_groups.Tables[0].Columns.Add("user_name");
_groups.Tables[0].Columns.Add("id_group", typeof(int));
_groups.Tables[1].Columns.Add("id_group", typeof(int));
_groups.Tables[1].Columns.Add("group_name");
_groups.Tables[0].Rows.Add(1, "Nom1", 1);
_groups.Tables[0].Rows.Add(2, "Nom2", 2);
_groups.Tables[0].Rows.Add(3, "Nom3", null);
_groups.Tables[1].Rows.Add(1, "Group1");
_groups.Tables[1].Rows.Add(2, "Group2");
Console.WriteLine(_groups.GetXml());
var result = _groups.Tables[0].AsEnumerable()
.Where(user => user.Field<int>("id_user") == 1)
.Join(_groups.Tables[1].AsEnumerable(), user => user.Field<int?>("id_group"), group => group.Field<int>("id_group"), (user, group) => new { id_user = user.Field<int>("id_user"), group_name = group.Field<string>("group_name") }).First();
Console.WriteLine(result.group_name);
var result2 = _groups.Tables[0].AsEnumerable()
.Where(user => user.Field<int>("id_user") == 3)
.Join(_groups.Tables[1].AsEnumerable(), user => user.Field<int?>("id_group"), group => group.Field<int>("id_group"), (user, group) => new { id_user = user.Field<int>("id_user"), group_name = group.Field<string>("group_name") }).FirstOrDefault();
Console.WriteLine(result2 != null? result2.group_name:null);
Console.ReadLine();
My EF query is supposed to be sorting by the date of the first Product in the list, but for some reason, it only sorts most of the products and some of the dates are in the wrong order.
Here's the code...
using (var context = new SalesEntities())
{
var groupedData = context.s84_Schedule.AsExpandable()
.Where(predicate)
.GroupBy(c => new { c.CustomerID, c.s84_Customer.CustomerName, c.SubdivisionID, c.s84_Subdivision.SubdivisionName, c.LotNumber })
.Select(grouped => new s84_Report_Project_POCO
{
CustomerID = grouped.Key.CustomerID,
CustomerName = grouped.Key.CustomerName,
SubdivisionID = grouped.Key.SubdivisionID,
SubdivisionName = grouped.Key.SubdivisionName,
LotNumber = grouped.Key.LotNumber,
Products = grouped.Select(x => new s84_Report_Project_Product
{
ProductID = x.ProductID,
ProductName = x.s84_Product.ProductName,
ProductDate = x.CustomerExpectedDate,
FieldRepID = x.FieldRepID,
FieldRepName = x.s84_FieldRep.FieldRepName,
InstallerID = x.InstallerID,
InstallerName = x.s84_Installer.InstallerName,
StatusID = x.StatusID,
StatusColor = x.s84_Status.StatusColor,
StatusName = x.s84_Status.StatusName,
Completed = x.Completed
}).ToList()
});
var finalList = groupedData.ToList().Where(x => x.Products.Last().Completed == false).ToList();
List<s84_Report_Project_POCO> lst = finalList.OrderBy(x => x.Products.First().ProductDate).ToList();
return lst;
}
Code seems good to me, but look at how one of the dates is out of order...
weird sorting http://www.84sales.com/weird_sort.png
Try doing the order by on the inital select
var groupedData = context.s84_Schedule.AsExpandable()
.Where(predicate)
.GroupBy(c => new { c.CustomerID,
c.s84_Customer.CustomerName,
c.SubdivisionID,
c.s84_Subdivision.SubdivisionName,
c.LotNumber })
.Select(grouped => new s84_Report_Project_POCO
{
CustomerID = grouped.Key.CustomerID,
CustomerName = grouped.Key.CustomerName,
SubdivisionID = grouped.Key.SubdivisionID,
SubdivisionName = grouped.Key.SubdivisionName,
LotNumber = grouped.Key.LotNumber,
Products = grouped
.Select(x => new s84_Report_Project_Product
{
ProductID = x.ProductID,
ProductName = x.s84_Product.ProductName,
ProductDate = x.CustomerExpectedDate,
FieldRepID = x.FieldRepID,
FieldRepName = x.s84_FieldRep.FieldRepName,
InstallerID = x.InstallerID,
InstallerName = x.s84_Installer.InstallerName,
StatusID = x.StatusID,
StatusColor = x.s84_Status.StatusColor,
StatusName = x.s84_Status.StatusName,
Completed = x.Completed
}).OrderBy(x => x.CustomerExpectedDate).ToList()
});
The problem is the .First() function, witch returns the first record, but not necessarly in date order. if you wich to order your grouped datas by date so that the First() function returns the most recent date, you'll need to order your datas before grouping them, and then REorder your results with the First()function :
using (var context = PrimaryConnection.returnNewConnection())
{
var groupedData = context.s84_Schedule.AsExpandable()
.Where(predicate)
.GroupBy(c => new { c.CustomerID, c.s84_Customer.CustomerName, c.SubdivisionID, c.s84_Subdivision.SubdivisionName, c.LotNumber })
.Select(grouped => new s84_Report_Project_POCO
{
CustomerID = grouped.Key.CustomerID,
CustomerName = grouped.Key.CustomerName,
SubdivisionID = grouped.Key.SubdivisionID,
SubdivisionName = grouped.Key.SubdivisionName,
LotNumber = grouped.Key.LotNumber,
Products = grouped
.Select(x => new s84_Report_Project_Product
{
ProductID = x.ProductID,
ProductName = x.s84_Product.ProductName,
ProductDate = x.CustomerExpectedDate,
FieldRepID = x.FieldRepID,
FieldRepName = x.s84_FieldRep.FieldRepName,
InstallerID = x.InstallerID,
InstallerName = x.s84_Installer.InstallerName,
StatusID = x.StatusID,
StatusColor = x.s84_Status.StatusColor,
StatusName = x.s84_Status.StatusName,
Completed = x.Completed
}).Orderby(t => t.CustomerExpectedDate).ToList()
});
var finalList = groupedData.ToList().Where(x => x.Products.Last().Completed == false).ToList();
List<s84_Report_Project_POCO> lst = finalList.OrderBy(x => x.Products.First().ProductDate).ToList();
All SQL queries (and hence Linq queries, when attached to a SQL database) have a random order, unless you sort them.
Products is not sorted - hence it has a random order.
You sort by Products.First(), but Products has a random order, so your sort will also be random.
Make sure Products is sorted within the query, and you should be ok.
Products = grouped.Select(....)
.OrderBy(x => x.ProductDate)
.ToList()
I am using LINQ to entitiy in my project.
I have this LINQ:
var result = (from inspArch in inspectionArchives
from inspAuth in inspArch.InspectionAuthority
select new
{
Id = inspArch.Id,
clientId = inspArch.CustomerId,
authId = inspAuth.Id
}).ToList();
After LINQ is executed result has this value :
Is there any elegant way (for example using LINQ or change above existing LINQ) to create from the list above, new list like that:
I haven't built this to see if it compiles, but this should work. You need to aggregate the Id and AuthId fields.
var result = (from inspArch in inspectionArchives
from inspAuth in inspArch.InspectionAuthority
select new
{
Id = inspArch.Id,
clientId = inspArch.CustomerId,
authId = inspAuth.Id
})
.GroupBy(g => g.clientId)
.select(s => new {
Id = string.Join(",", s.Select(ss => ss.Id.ToString())),
ClientId = s.Key,
AuthId = string.Join(",", s.Select(ss => ss.authId.ToString()).Distinct()),
}).ToList();
You need group by and you can apply String.Join on the resulting IGrouping:-
var result = (from inspArch in inspectionArchives
from inspAuth in inspArch.InspectionAuthority
group new { inspArch, inspAuth } by inspArch.CustomerId into g
select new
{
Id = String.Join(",",g.Select(x => x.inspArch.Id),
clientId = x.Key,
authId = String.Join(",",g.Select(x => x.inspAuth.Id)
}).ToList();
The tricky part here is to group both objects i.e. new { inspArch, inspAuth } because we need to access properties from both.
Update:
Since this is entity framework, it won't be able to translate the method String.Join to SQL, so we can bring back the grouped object to memory using AsEnumerable and then project it like this:-
var result = (from inspArch in inspectionArchives
from inspAuth in inspArch.InspectionAuthority
group new { inspArch, inspAuth } by inspArch.CustomerId into g
select g).AsEnumerable()
.Select(g => new
{
Id = String.Join(",",g.Select(x => x.inspArch.Id),
clientId = x.Key,
authId = String.Join(",",g.Select(x => x.inspAuth.Id)
}).ToList();
I'm struggling with GroupBy and Sum in the following query using SelectMany. Could someone show me how to sum two fields as well as how to group by and order by several fields.
var Rows = allData.SelectMany(u => u._rows.Select(t => new
{
OA = t[4],
CD = t[5],
PD = t[0],
DS = Convert.ToInt32(t[9]),
CS = Convert.ToInt32(t[10])
}))
// Pseudo-code:
//.GroupBy(CD)
//.GroupBy(OA)
//.GroupBy(PD)
//.Sum(u=> u.DS)
//.Sum(u => u.CS)
.OrderBy(u => u.CD)
.ThenBy(u => u.OA)
.ThenBy(u => u.PD)
.ToList();
Object:
List<DataProperty> allData = new List<DataProperty>();
DataProperty consists of
private readonly Dictionary<string, string> _headers = new Dictionary<string, string>();
private readonly List<string[]> _rows = new List<string[]>();
The original query before the C# rewrite from ColdFusion:
SELECT
OA,
CD,
PD,
sum(DS) as DS
sum(CS) as CS
FROM qDistinct
GROUP BY
CD,
OA,
PD
ORDER BY
ucaseCD,
OA,
PD
If the GroupBy is coded differently in the following query without Sum, could you also please show me how to do it?
var Rows = allData.SelectMany(u => u._rows.Select(t => new
{
OA = t[4],
PD = t[0]
}))
// Pseudo-code:
//.GroupBy(OA)
//.GroupBy(PD)
.OrderBy(u => u.OA)
.ThenBy(u => u.PD)
.ToList();
It's not very clear what you want - something like this?
var Rows = allData.SelectMany(u => u._rows.Select(t => new
{
OA = t[4],
CD = t[5],
PD = t[0],
DS = Convert.ToInt32(t[9]),
CS = Convert.ToInt32(t[10])
}))
// group by the combination of CD, OA, and PD
.GroupBy(x => new { x.CD, x,OA, x.PD } )
// sum DS and CS within each group
.Select (g => new {g.Key.CD,
g.Key.OA,
g.Key.PD,
DS = g.Sum(u=> u.DS),
CS = g.Sum(u=> u.CS)
} )
.OrderBy(u => u.CD)
.ThenBy(u => u.OA)
.ThenBy(u => u.PD)