Read groupname for specific user in asp net linq - c#

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

Related

How to use GroupBy() in subqueries with LINQ?

I have pretty simple LINQ expression
IQueryable<FreeBetDTO> records = UnitOfWork.FreeBets
.Include(f => f.FreeBetCategories)
.Include(f => f.FreeBetCards)
.Where(f => f.FreeBetCards.Any(cards => cards.UserId == request.UserId))
.Select(f => new FreeBetDTO
{
FreeBetId = f.FreeBetId
LineCategories = f.FreeBetCategories
.GroupBy(g => new { g.LineCategoryID, g.Title })
.Select(c =>
new LineCategoryDTO
{
LineCategoryID = c.Key.LineCategoryID,
Title = c.Key.Title
}).AsEnumerable()
});
When I am executing it I catch the error:
System.InvalidOperationException: Unable to translate collection subquery in projection since it uses 'Distinct' or 'Group By' operations and doesn't project key columns of all of it's tables which are required to generate results on client side. Missing column: t.ID. Either add column(s) to the projection or rewrite query to not use 'GroupBy'/'Distinct' operation.
at Microsoft.EntityFrameworkCore.Query.SqlExpressions.SelectExpression.
....
The problem is here .GroupBy(g => new { g.LineCategoryID, g.Title }). If I don't group records, the error disappears.
I was trying a lot of cases with GroupBy() and Distinct(). But can't understand why this is happening. Because I just need grouping like this.
Error message says that you have to include Id column in projection. But you can't do that with GroupBy. So rewrite query into two steps (removed not needed includes):
var rawRecords = UnitOfWork.FreeBets
.Where(f => f.FreeBetCards.Any(cards => cards.UserId == request.UserId))
.Select(f => new
{
FreeBetId = f.FreeBetId
LineCategories = f.FreeBetCategories.Select(c => new { c.Id, c.LineCategoryID, c.Title })
.ToList()
})
.AsEnumerable();
var records = rawRecords
.Select(f => new FreeBetDTO
{
FreeBetId = f.FreeBetId
LineCategories = f.LineCategories.GroupBy(g => new { g.LineCategoryID, g.Title })
.Select(c =>
new LineCategoryDTO
{
LineCategoryID = c.Key.LineCategoryID,
Title = c.Key.Title
})
});
Similar query, but more optimal:
var query =
from f in UnitOfWork.FreeBets
from c in f.FreeBetCards
where f.FreeBetCards.Any(cards => cards.UserId == request.UserId)
select new { f.FreeBetId, c.LineCategoryID, c.Title };
query = query.Distinct();
var records = query.AsEnumerable()
.GroupBy(f => f.FreeBetId)
.Select(g => new FreeBetDTO
{
FreeBetId = g.Key
LineCategories = g.Select(c =>
new LineCategoryDTO
{
LineCategoryID = c.LineCategoryID,
Title = c.Title
})
.AsEnumerable()
});

How can i modify this query to leave out blanks or empty value?

This query is used to select distinct value from a table in the database
public List<SubDepartmentViewModel> GetSubDepartments()
{
var query = _db.SendersReceivers.Select(a => new SubDepartmentViewModel
{
SubDepartmentName = a.SubDepartment //column in the database
})
.Distinct().ToList();
return query;
}
var query = _db.SendersReceivers
.Where(a => !string.IsNullOrEmpty(a.SubDepartment))
.Select(a => new SubDepartmentViewModel
{
SubDepartmentName = a.SubDepartment
})
.Distinct().ToList();
This should do the trick.

Lambda Join Group by where clause issue

Why am I getting only one entry in DownTimeDetails list even though in Data we have 3 entries.
VehicleEventDetails Res = dbEntity.DownTimeHeaders
.Join(dbEntity.DownTimeDetails, dth => dth.DownTimeHeaderID, dtd => dtd.DownTimeHeaderID, (dth, dtd) => new { dth, dtd })
.Where(x => x.dth.DownTimeHeaderID == 42)
.GroupBy(gx => gx.dtd.DownTimeDetailID)
.Select(t => new VehicleEventDetails()
{
BookingId = t.Select(a => a.dth.BookingId).FirstOrDefault(),
DownTimeDetails = t.Select(ab => new DownTimeDetails
{
LocalDTStartTime = (DateTime)ab.dtd.LocalDTStartTime,
LocalDTEndTime = (DateTime)ab.dtd.LocalDTEndTime,
CalculatedEventDTReason = ab.dtd.CalculatedEventDTReason,
CalculatedEventDTInMinutes = (int)ab.dtd.CalculatedEventDT,
}).ToList()
}).FirstOrDefault();
You are looking for something like this:
VehicleEventDetails Res = dbEntity.DownTimeHeaders
.Where(x => x.DownTimeHeaderID == 42)
.Select(x => new VehicleEventDetails
{
BookingId = x.BookingId,
DownTimeDetails = x.DownTimeDetails
.Select(dtd=> new DownTimeDetails
{
LocalDTStartTime = (DateTime)dtd.LocalDTStartTime,
LocalDTEndTime = (DateTime)dtd.LocalDTEndTime,
CalculatedEventDTReason = dtd.CalculatedEventDTReason,
CalculatedEventDTInMinutes = (int)dtd.CalculatedEventDT,
})
.ToList()
})
.FirstOrDefault();
Notes:
Using .Join is an anti-Entity Framework pattern. Always try to use navigation properties, they exist for a reason.
Don't use .GroupBy unless you actually need a group. You don't want any grouping in this query.
As a general note, try not to make the expression variable names so confusing.

LINQ Method - Optimization

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.

How to select data in rows using LINQ?

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

Categories

Resources