Group Concatenation with Linq - linq

I have this:
var lstAssignmentDetails =
(from t1 in _unitOfWork.ReferralDetailsRepository.Get()
.Where(m => (m.ChartStatusID == (int)Utility.ReferralChartStatus.NotStaffed
|| m.ChartStatusID == (int)Utility.ReferralChartStatus.Partially_Staffed
|| m.ChartStatusID == (int)Utility.ReferralChartStatus.Restaff)
&& m.IsDeleted == false).OrderByDescending(x => x.ReferralDetailsId)
join t2 in _unitOfWork.ReferralRepository.Get() on t1.ReferralId equals t2.ReferralId
join t3 in _unitOfWork.PatientRepository.Get() on t2.PatientId equals t3.PatientId
join t4 in _unitOfWork.ClientRepository.Get() on t2.ClientId equals t4.ClientID
join t5 in _unitOfWork.DisciplineRepository.Get() on t1.DesciplineID equals t5.DesciplineID
join t6 in _unitOfWork.UserRepository.Get() on t2.CreatedBy equals t6.UserID
join t7 in _unitOfWork.PersonRepository.Get() on t6.PersonID equals t7.PersonID
join rt in _unitOfWork.ReferralTherapistRepository.Get() on t2.ReferralId equals rt.ReferralId
join t in _unitOfWork.TherapistRepository.Get() on rt.TherapistId equals t.TherapistId
join u in _unitOfWork.UserRepository.Get() on t.UserId equals u.UserID
join p in _unitOfWork.PersonRepository.Get() on u.PersonID equals p.PersonID
select new ReferralTempModel()
{
ReferralId = t1.ReferralId,
ClientName = t4.ClientName,
PatientName = t3.LastName + "," + t3.FirstName,
RefferalDate = t2.RefferalDate,
DisciplineID = t1.DisciplineID,
ReferralDetailsId = t1.ReferralDetailsId,
PatientId = t2.PatientId,
ClientID = t4.ClientID,
DiscName = t5.DesciplineType,
IsRejected = t1.IsRejected,
CreatedBy = t7.LastName + "," + t7.FirstName,
ChartstatusId = t1.ChartStatusID.Value
}).ToList();
return lstAssignmentDetails;
There are multiple ReferralTherapists for each referral. I need all the ReferralTherapists for each referral to be concatenated into one field. Essentially what I want to do is a GROUP_CONCAT using LINQ.
I know this is probably a duplicate, but none of the previous questions handles anything as complicated as this. Trying to add GroupBy always seems to create an error no matter where I place it.

Start by not joining other referrals as t2 when constructing your flat list, and adding therapist's name to the anonymous type:
var flatListAssignmentDetails =
(from t1 in _unitOfWork.ReferralDetailsRepository.Get()
.Where(m => (m.ChartStatusID == (int)Utility.ReferralChartStatus.NotStaffed
|| m.ChartStatusID == (int)Utility.ReferralChartStatus.Partially_Staffed
|| m.ChartStatusID == (int)Utility.ReferralChartStatus.Restaff)
&& !m.IsDeleted)
join t2 in _unitOfWork.ReferralRepository.Get() on t1.ReferralId equals t2.ReferralId
join t3 in _unitOfWork.PatientRepository.Get() on t2.PatientId equals t3.PatientId
join t4 in _unitOfWork.ClientRepository.Get() on t2.ClientId equals t4.ClientID
join t5 in _unitOfWork.DisciplineRepository.Get() on t1.DesciplineID equals t5.DesciplineID
join t6 in _unitOfWork.UserRepository.Get() on t2.CreatedBy equals t6.UserID
join t7 in _unitOfWork.PersonRepository.Get() on t6.PersonID equals t7.PersonID
select new {
t1.ReferralId,
t4.ClientName,
PatientName = t3.LastName + "," + t3.FirstName,
t2.RefferalDate,
t1.DisciplineID,
t1.ReferralDetailsId,
t2.PatientId,
t4.ClientID,
DiscName = t5.DesciplineType,
t1.IsRejected,
CreatedBy = t7.LastName + "," + t7.FirstName,
ChartstatusId = t1.ChartStatusID.Value,
TherapistName = p.LastName + "," + p.FirstName
}).ToList();
Now you can group your list, and concatenate therapist names:
var listAssignmentDetails = flatListAssignmentDetails
.GroupBy(r => r.ReferralId)
.Select(g => new ReferralTempModel {
ReferralId = g.First().ReferralId,
ClientName = g.First().ClientName,
PatientName = g.First().PatientName,
RefferalDate = g.First().RefferalDate,
DisciplineID = g.First().DisciplineID,
ReferralDetailsId = g.First().ReferralDetailsId,
PatientId = g.First().PatientId,
ClientID = g.First().ClientID,
DiscName = g.First().DiscName,
IsRejected = g.First()..IsRejected,
CreatedBy = g.First().CreatedBy,
ChartstatusId = g.First().ChartStatusID,
TherapistNames = string.Join(", ", g.Select(r => r.TherapistName))
}).ToList();
One thing to note here is that all fields that are tied to all referrals in the group are obtained through g.First() construct. The field with "group concatenation" is produced using string.Join method on a projection of TherapistName from the group.

Related

how to combine two linq to entity queries in just one query?

var CJTDebTransaction = from d in db.DebtorTransactions
join c in db.CarJackaTrackas on d.ProductID equals c.pkfCjtID
join a in db.Agents on c.AgentID equals a.pkfAgentID
join s in db.SalesReps on c.SalesRepId equals s.pkfSrID
where d.TransTypeID==1 && d.Product==1
select new { d.Amount, d.TransTypeID, Name=a.Name.Trim(), a.pkfAgentID,s.pkfSrID,salesrepName=s.Name} into debtRec
group debtRec by new { debtRec.TransTypeID, debtRec.Name, debtRec.pkfAgentID,debtRec.salesrepName,debtRec.pkfSrID} into debtRecGroup
orderby debtRecGroup.Key.Name
select new
{
Sum= debtRecGroup.Sum(model=>model.Amount),
TransTypeId=debtRecGroup.Key.TransTypeID ,
AgentId=debtRecGroup.Key.pkfAgentID,
AgentName=debtRecGroup.Key.Name,
SalesrepId=debtRecGroup.Key.pkfSrID,
SalesRepName=debtRecGroup.Key.salesrepName
};
var WntyDebTransaction = from d in db.DebtorTransactions
join w in db.Warranties on d.ProductID equals w.Id
join a in db.Agents on w.fldAgentID equals a.pkfAgentID
join s in db.SalesReps on w.fldSrId equals s.pkfSrID
where d.TransTypeID == 1 && d.Product == 0
select new { d.Amount, d.TransTypeID, Name=a.Name.Trim(), a.pkfAgentID, s.pkfSrID, salesrepName = s.Name } into debtRec
group debtRec by new { debtRec.TransTypeID, debtRec.Name, debtRec.pkfAgentID, debtRec.salesrepName, debtRec.pkfSrID } into debtRecGroup
orderby debtRecGroup.Key.Name
select new
{
Sum = debtRecGroup.Sum(model => model.Amount),
TransTypeId = debtRecGroup.Key.TransTypeID,
AgentId = debtRecGroup.Key.pkfAgentID,
AgentName = debtRecGroup.Key.Name.Trim(),
SalesrepId = debtRecGroup.Key.pkfSrID,
SalesRepName = debtRecGroup.Key.salesrepName
}
I need to get the output in just one query, i new to linq to entity. i need the result like:- AgentName SalesRepName Debit Total(the total of amount where Product == 0) Credit Total(total of amount where Product==1) Outstanding Total(the difference between Debit Total and Credit Total). any suggestion will be appreciable. thanks in advance :)

Doing 2 Left Joins on the same table with one call

I have the following tables:
Users:
userId, userFirstName, userLastName.
holdBilling:
bEntityID, CarrierOID, PayerOID, holdTYPE, createUserID.
carrier:
carrierOID, carrierName.
payer:
payerOID, payerName.
I want the code to save in a new entity
holdBilling => new
{
FirstName, LastName, CarrierName, PayerName
}
One of these Entities has either a payer or a carrier value (cannot have both). Basically i want to make 2 left joins on the same table with one call. This would be the SQL query that would work for me.
SELECT TOP 1000 [ID]
,[bEntityID]
,c.carrierID
,c.carrierName
,p.payerID
,p.payerName
,[holdType] ( this is "C" for carrier and "P" for payer )
FROM .[dbo].[holdBilling] hb
left join dbo.payer p on hb.payerID = p.payerID
left join dbo.carrier c on hb.carrierID = c.carrierID
where [bEntityID] = 378
The temporary solution I've found is getting a list of all Carriers
var listC = (from hold in holdBilling
join u in Users on hold.createUserID equals u.userID
join c in carrier.DefaultIfEmpty() on hold.carrierID equals c.carrierID
select new
{
Elem = hold,
FName = u.userFirstName,
LName = u.userLastName,
Carrier = c.carrierName,
Payer = ""
}).ToList();
and one for all payers
select new
{
Elem = hold,
FName = u.userFirstName,
LName = u.userLastName,
Carrier = "",
Payer = p.payerName
}).ToList();
and merging the two,I'm confident there has to be a solution for doing both in one query.
Something like this maybe:
var listC = (
from hb in holdBilling
from p in payer.Where(a=>a.payerID==hb.payerID).DefaultIfEmpty()
from c in carrier.Where(a=>a.carrierID=hb.carrierID).DefaultIfEmpty()
where hb.bEntityID==378
select new
{
hb.bEntityID,
c.carrierID,
c.carrierName,
p.payerID,
p.payerName,
holdType=(payer==null?"P":"C")
}
).Take(1000)
.ToList();
You need to use DefaultIfEmpty to do a left join
var listC = (from hold in holdBilling
from u in Users.Where(x => hold.createUserID == x.userID).DefaultIfEmpty()
from c in carrier.Where(x => hold.carrierID == x.carrierID).DefaultIfEmpty()
select new
{
Elem = hold,
FName = u.userFirstName,
LName = u.userLastName,
Carrier = c.carrierName,
Payer = ""
}).ToList();

LINQ 2 lefts joins with Sum

I am trying to do a relatively straight forward SQL query with linq:
SELECT ir.resource_id, r.first_name, r.surname, rt.job_title, SUM(plan_ts_hours), SUM(ts_hours) FROM tbl_initiative_resource ir
INNER JOIN tbl_resource r ON ir.resource_id = r.resource_id
INNER JOIN tbl_resource_type rt ON rt.resource_type_id = r.resource_type_id
LEFT JOIN tbl_plan_timesheet pts on pts.resource_id = ir.resource_id AND pts.initiative_id = ir.initiative_id
LEFT JOIN tbl_timesheet ts on ts.resource_id = ir.resource_id AND ts.initiative_id = ir.initiative_id
WHERE ir.initiative_id = 111
GROUP BY ir.resource_id, r.first_name, r.surname, rt.job_title
After reading this blog: http://smehrozalam.wordpress.com/2010/04/06/linq-how-to-build-complex-queries-utilizing-deferred-execution-and-anonymous-types/
I came up with the following linq:
var query = (from initRes in Context.tbl_initiative_resource
join res in Context.tbl_resource on initRes.resource_id equals res.resource_id
join resType in Context.tbl_resource_type on res.resource_type_id equals resType.resource_type_id
from tsheet in Context.tbl_timesheet.Where(x => x.resource_id == initRes.resource_id).Where(x => x.initiative_id == initRes.initiative_id).DefaultIfEmpty()
from plannedtsheet in Context.tbl_plan_timesheet.Where(x => x.resource_id == initRes.resource_id).Where(x => x.initiative_id == initRes.initiative_id).DefaultIfEmpty()
where initRes.initiative_id == initiativeID
group new { ID = res.resource_id, ResourceType = resType.job_title, Times = tsheet, P = plannedtsheet } by initRes.resource_id into g
select new
{
ResourceID = g.Key,
Hours = g.Sum(x => (decimal?)x.Times.ts_hours),
PlannedHours = g.Sum(x => (decimal?)x.P.plan_ts_hours)
}).ToList();
Any ideas on how I can access the ResourceType when selecting the new anonymous type?
ResourceType is part of the the grouping key, so g.Key.ResourceType should do it.
(Check out the type of ResouceID in the results, as you've assigned it g.Key it will be an instance of the (anonymous) type created in the group clause.

Linq left outer join across multiple tables retrieving info from each table

I am new to linq and want to perform joins across three tables. The sql equivalent of what I am trying to do is:
SELECT PM.Id, PM.new_clientId, .....
C.new_firstname, c.new_surname,.....
A.new_addressid, A.new_addressline1, A.new_addressline2.....
CY.new_county
FROM partialMatch PM
INNER JOIN new_client C ON PM.new_clientId = C.new_clientId
LEFT OUTER JOIN new_address A ON C.new_addressId = A.new_addressId
LEFT OUTER JOIN new_county CY ON A.new_countyId = CY.new_countyId
WHERE PM.ownerId = #UserId AND PM.new_reviewed <> true
The linq code I have developed is this, but these don't seem to be outer join as it is not returning any results unless I comment out the joins to the address and county table
var partialMatches = from pm in ContextService.CreateQuery<new_partialmatch>()
join c in ContextService.CreateQuery<new_client>() on pm.new_ClientId.Id equals c.new_clientId
join a in ContextService.CreateQuery<new_address>() on c.new_AddressID.Id equals a.new_addressId
join cy in ContextService.CreateQuery<new_county>() on a.new_CountyID.Id equals cy.new_countyId
where pm.OwnerId.Id == _currentUserId && pm.new_Reviewed != true
select new
{
Id = pm.Id,
new_ClientID = pm.new_ClientId,
new_MatchingCRMClientID = pm.new_MatchingCRMClientId,
new_MatchingVulcanClientID = pm.new_MatchingVulcanClientID,
new_name = pm.new_name,
firstname = c.new_FirstName,
surname = c.new_Surname,
dob = c.new_DateOfBirth,
addressId = a.new_addressId,
address1 = a.new_AddressLine1,
address2 = a.new_AddressLine2,
address3 = a.new_AddressLine3,
address4 = a.new_AddressLine4,
county = cy.new_County
};
Any help would be greatly appreciated,
Thanks,
Neil
EDIT:
I also tried using the 'into' statement but then on my second join the alias isn't recognised.
from pm in ContextService.CreateQuery<new_partialmatch>()
join c in ContextService.CreateQuery<new_client>() on pm.new_ClientId.Id equals c.new_clientId into pmc
from x in pmc.DefaultIfEmpty()
join a in ContextService.CreateQuery<new_address>() on c.new_AddressID.Id equals a.new_addressId
So for the c.newIddressID.Id equals a.new_addressId I get this error message:
The name 'c' is not in scope on the left side of 'equals'. Consider swapping the expressions on either side of 'equals'.
var addressCountryQuery = from a in ContextService.CreateQuery<new_address>()
from cy in ContextService.CreateQuery<new_county>().Where( cy => cy.new_countyId == a.new_CountyID.Id).DefaultIfEmpty()
select new
{
addressId = a.new_addressId,
address1 = a.new_AddressLine1,
address2 = a.new_AddressLine2,
address3 = a.new_AddressLine3,
address4 = a.new_AddressLine4,
county = cy.new_County
}
var partialMatches = from pm in ContextService.CreateQuery<new_partialmatch>()
join c in ContextService.CreateQuery<new_client>() on pm.new_ClientId.Id equals c.new_clientId
from a in addressCountryQuery .Where( a => a.addressId == c.new_AddressID.Id).DefaultIfEmpty()
where pm.OwnerId.Id == _currentUserId && pm.new_Reviewed != true
select new
{
Id = pm.Id,
new_ClientID = pm.new_ClientId,
new_MatchingCRMClientID = pm.new_MatchingCRMClientId,
new_MatchingVulcanClientID = pm.new_MatchingVulcanClientID,
new_name = pm.new_name,
firstname = c.new_FirstName,
surname = c.new_Surname,
dob = c.new_DateOfBirth,
addressId = a.addressId,
address1 = a.AddressLine1,
address2 = a.AddressLine2,
address3 = a.AddressLine3,
address4 = a.AddressLine4,
county = a.County
};
See how I modified the join for a and cy so I could add the DefultIfEmpty method.
I split the two outer joins in to one query and then join that query back into the original query.

linq projection

I'm building a linq query using join and into statements.
var testmyquery = from uf in TheFolderModel.UserFolders
where (uf.UserID == TheUserID)
join ul in TheFolderModel.UserBooksheets on
uf.FolderID equals ul.FolderID
join ll in TheFolderModel.BooksheetBooks on
ul.BooksheetID equals ll.BooksheetID
join ua in TheFolderModel.BooksAppointments on
ll.BookID equals ua.BookID
group ua.BookID by uf.FolderID into Holdingvar
orderby Holdingvar.Key
select new { TheCount = Holdingvar.Count(), Holdingvar.Key };
I need to add columns from tables in uf and ul to the retuning object but once I've got a projection on Holdingvar, the intellisense doesn't give me access to uf or ul anymore when I'm in the select new{} statement. How do I add columns in the select statement?
Thanks.
I got it:
var testmyquery = from uf in TheFolderModel.UserFolders
where (uf.UserID == TheUserID)
join ul in TheFolderModel.UserBooksheets on
uf.FolderID equals ul.FolderID
join ll in TheFolderModel.BooksheetBooks on
ul.BooksheetID equals ll.BooksheetID
join ua in TheFolderModel.BooksAppointments on
ll.BookID equals ua.BookID
group ua.BookID by uf.FolderID into Holdingvar
orderby Holdingvar.Key
from uf2 in TheFolderModel.UserFolders
where uf2.FolderID == testg.Key
select new { testk = testg.Count(), testg.Key, uf2.FolderName };
I just needed to redefine a variable after I did the projection in the holding variable.
You can't...once you select new {..., the uf and ul are out of scope.
I'm not sure if this would work for you, but if you need the count and key, you could do a let statement:
var testmyquery = from uf in TheFolderModel.UserFolders
where (uf.UserID == TheUserID)
join ul in TheFolderModel.UserBooksheets on
uf.FolderID equals ul.FolderID
join ll in TheFolderModel.BooksheetBooks on
ul.BooksheetID equals ll.BooksheetID
join ua in TheFolderModel.BooksAppointments on
ll.BookID equals ua.BookID
group ua.BookID by uf.FolderID into Holdingvar
orderby Holdingvar.Key
let someproperty = new { TheCount = Holdingvar.Count(), Holdingvar.Key }
select new { uf.UserID, ........ }
I do this all the time. Why is it not working for you? The structure of my query is a bit different. Perhaps you need to reform it?
var q = (from at in Repository.For<AuditTrailEntity>()
from att in Repository.For<AuditTrailTypeEntity>()
join ue in Repository.For<UserEntity>() on at.UserId equals ue.RowId
join up in Repository.For<UserProfileEntity>() on ue.AspnetUserId equals up.UserId
where (at.AffectedEntityName == "AssetEntity" && at.PKId == assetId.ToString() && at.ActionType == att.RowId)
orderby at.CreatedDate descending
select new AssetAuditTrailModel
{
RowId = at.RowId,
AffectedEntityName = at.AffectedEntityName,
PKId = at.PKId,
ActionType = at.ActionType,
ActionData = at.ActionData,
UserId = at.UserId,
CreatedDate = at.CreatedDate,
ActionName = att.FriendlyName,
UserName = up.FirstName + " " + up.LastName,
});

Resources