linq 2 left joins - linq

So I wanted to make a linq query out of my left join sql (refer to it below). I just don't know how to properly position the ".TournamentId = 1" condition on the joins. Currently when running this on my database I get the results that I want. which is a couple of rows from the Type table with null fields.
select typ.Id, stat.PromoterId, temp.PromoterId
from ReportTypes type
left join ReportTemplateStatus status on status.PromoterId = type.TypeId and status.TournamentId = 1
left join ReportTemplates temp on temp.ClientId = status.PromoterId and temp.TournamentId = 1
Promoter
- promoterId
- promoterName
Tournament
- tournamentId
- tournamentName
ReportType
- TypeId
ReportTemplateStatus
- promoterId (this is the key)
- tournamentId
- typeId
ReportTemplates
- promoterId
- tournamentId
This is currently what I have:
var report = from type in context.ReportTypes
join status in context.ReportTemplateStatus on type.TypeId equals status.TypeId
join temp in context.ReportTemplates on status.promoterId equals temp.promoterId into iReports
from reports in iReports.Where (rep => rep.promoterId == _promoterId && rep.tournamentId == _tournamentId).DefaultIfEmpty()
select new { my fields});
but it's giving me a null.
any ideas on how the linq should work? maybe separate into "itables" (iReports) or something?

This should give you what you are looking for
var report = from type in context.ReportTypes
from status in context.ReportTemplateStatus.Where(x => type.TypeId == x.TypeId)
.Where(x => x.TournamentId == 1)
.DefaultIfEmpty()
from reports in context.ReportTemplates.Where(x => status.promoterId == x.promoterId)
.Where(x => x.TournamentId == 1)
.DefaultIfEmpty()
select new { my fields};

You can use like this
var query = from person in people
join pet in pets on person equals pet.Owner into gj
from subpet in gj.DefaultIfEmpty()
select new { person.FirstName, PetName = (subpet == null ? String.Empty : subpet.Name) };
Thanks

Related

Left joining a table's id with the maximum id from a subquery

I am using .NET core and trying to write a Linq query to list Cases. I have 3 tables that I am trying to join together:
Cases - Includes CaseID and CaseStatusID
CaseStatuses - Includes CaseStatusID (a Case has one of these)
CaseStatusHistory - Includes CaseStatusHistoryID, CaseID, CaseStatusID (a Case has many of these).
I can join Cases and CaseStatuses easily on CaseStatusID but am not sure how to join CaseStatusHistory on CaseStatusHistoryID = a subquery selecting the MAX(CaseStatusHistoryID) WHERE CaseID and CaseStatusID matches. I could even select the CaseStatusHitory later in my results but am not sure how.
This is what I need to convert
SELECT
c.CaseID,
csh.DateTimeAdded
FROM dbo.Cases c
JOIN dbo.CaseStatuses cs
ON c.CaseStatusID = cs.CaseStatusID
LEFT JOIN dbo.CaseStatusHistory csh
ON csh.CaseStatusHistoryID =
(
SELECT MAX(CaseStatusHistoryID)
FROM dbo.CaseStatusHistory
WHERE CaseID = c.CaseID
AND cs.CaseStatusID = c.CaseStatusID
)
This is what I have so far in Linq
IQueryable<CasesViewModel> objs =
from c in _db.Cases
from cs in _db.CaseStatuses.Where(cs => cs.CaseStatusId == c.CaseStatusId.Value).DefaultIfEmpty()
select new CasesViewModel
{
CaseID = c.CaseId,
CaseStatus = cs.CaseStatus
//StatusChangeDate = csh.DateTimeAdded
};
I need to add something like this
From csh In CaseStatusHistories
Where
(
From _csh In CaseStatusHistories
Where _csh.CaseID = c.CaseID AndAlso _csh.CaseStatusID = c.CaseStatusID
Select _csh.CaseStatusHistoryID
).Max = csh.CaseStatusHistoryID
Here is what I have so far but it does not return any result - just seems to time out.
IQueryable<CasesViewModel> objs =
from c in _db.Cases
from cs in _db.CaseStatuses.Where(cs => cs.CaseStatusId == c.CaseStatusId.Value).DefaultIfEmpty()
from rg in _db.RepairingGarages.Where(rg => rg.RepairingGarageId == c.RepairingGarageId.Value).DefaultIfEmpty()
from rgb in _db.Businesses.Where(rgb => rgb.BusinessId == rg.BusinessId.Value).DefaultIfEmpty()
from ec in _db.EngineeringCompanies.Where(ec => ec.EngineeringCompanyId == c.EngineeringCompanyId.Value).DefaultIfEmpty()
from ecb in _db.Businesses.Where(ecb => ecb.BusinessId == ec.BusinessId.Value).DefaultIfEmpty()
from csh in _db.CaseStatusHistory.Where(csh => csh.CaseStatusHistoryId ==
(
from _csh in _db.CaseStatusHistory
where _csh.CaseId == c.CaseId && _csh.CaseStatusId == c.CaseStatusId.Value
select _csh.CaseStatusHistoryId
).Max()).DefaultIfEmpty()
select new CasesViewModel
{
CaseID = c.CaseId,
RepairingGarage = rgb.BusinessName,
Engineer = ecb.BusinessName,
CaseStatus = cs.CaseStatus,
StatusChangeDate = csh.DateTimeAdded
};
I just need to get the StatusChangeDate which is the DateTimeAdded in the CaseStatusHistory table. Cases can be at the same status more than once, so I just need the DateTimeAdded with the highest CaseStatusHistoryID for a particular Case. Thank you very much for any help.
This appears to answer my question
IQueryable<CasesViewModel> objs =
from c in _db.Cases
from cs in _db.CaseStatuses.Where(cs => cs.CaseStatusId == c.CaseStatusId.Value).DefaultIfEmpty()
from rg in _db.RepairingGarages.Where(rg => rg.RepairingGarageId == c.RepairingGarageId.Value).DefaultIfEmpty()
from rgb in _db.Businesses.Where(rgb => rgb.BusinessId == rg.BusinessId.Value).DefaultIfEmpty()
from ec in _db.EngineeringCompanies.Where(ec => ec.EngineeringCompanyId == c.EngineeringCompanyId.Value).DefaultIfEmpty()
from ecb in _db.Businesses.Where(ecb => ecb.BusinessId == ec.BusinessId.Value).DefaultIfEmpty()
select new CasesViewModel
{
CaseID = c.CaseId,
RepairingGarage = rgb.BusinessName,
Engineer = ecb.BusinessName,
CaseStatus = cs.CaseStatus,
StatusChangeDate =
(
from _csh in _db.CaseStatusHistory
where _csh.CaseId == c.CaseId && _csh.CaseStatusId == cs.CaseStatusId
orderby _csh.CaseStatusHistoryId descending
select _csh.DateTimeAdded
).FirstOrDefault()
};
The only trouble with not joining is that I am not sure if I can sort by this date now. Any better ideas? Thank you.

LINQ Aggregate results with Many to Many Relationship

I am currently working with this schema
This is how my LINQ currently looks
var regionResults = (
from p in _context.Projects
from pr in p.Regions
where (data.RegionId == null || pr.RegionId == data.RegionId)
group p by pr.RegionId into g
join q in _context.Regions on g.Key equals _context.Regions.First().Id
select new Models.ViewModels.ProjectBreakdownViewModel.Regions
{
RegionName = q.Name,
TotalCount = g.Count(),
RejectedCount = g.Count(e => e.SubmissionStatusId == 2),
DeniedCount = g.Count(e => e.SubmissionStatusId == 3)
});
this is what it is currently producing, albeit incorrect
This is what I need it to be...
I know the problem is with this line, essentially
join q in _context.Regions on g.Key equals _context.Regions.First().Id
I don't know how to do this without the use of .First(), there doesn't seem to be a way to do it. I'm close I just don't know how to finish this.
If you have an collection of ProjectRegions in you Region entity, you can do this:
var result= context.Regions
.Where(r=> data.RegionId == null || r.Id == data.RegionId)
.Select(r=> new
{
RegionName = r.Name,
TotalCount = r.ProjectRegions.Count(),
RejectedCount = r.ProjectRegions.Count(e => e.Project.SubmissionStatusId == 2),
DeniedCount = r.ProjectRegions.Count(e => e.Project.SubmissionStatusId == 3)
});
ProjectRegion entity should have two nav properties, Project and Region, use them to navigate and create the corresponding conditions

how use multiple join in linq?

var abc1 = from dlist in db.DebtorTransactions.ToList()
join war in db.Warranties on dlist.ProductID equals war.Id
join ag in db.Agents on war.fldAgentID equals ag.pkfAgentID
join sr in db.SalesReps on war.fldSrId equals sr.pkfSrID
where dlist.TransTypeID == 1
select new
{
dlist.Amount,
dlist.TransTypeID,
name = ag.Name,
ag.pkfAgentID,
sr.pkfSrID,
salesnam = sr.Name
} into objabc
group objabc by new
{
objabc.TransTypeID,
objabc.name,
objabc.salesnam,
objabc.Amount
};
var amt1 = abc1.Sum(x => x.Key.Amount);
var abc2 = from dlist in db.DebtorTransactions.ToList()
join cjt in db.CarJackaTrackas on dlist.ProductID equals cjt.pkfCjtID
join ag in db.Agents on cjt.AgentID equals ag.pkfAgentID
join sr in db.SalesReps on cjt.SalesRepId equals sr.pkfSrID
where dlist.TransTypeID == 0
select new
{
dlist.Amount,
dlist.TransTypeID,
name = ag.Name,
ag.pkfAgentID,
sr.pkfSrID,
enter code here` salesnam = sr.Name
} into objabc
group objabc by new
{
objabc.TransTypeID,
objabc.name,
objabc.salesnam,
objabc.Amount
};
var amt2 = abc1.Sum(x => x.Key.Amount);
//var result1=
return View();
i am new to linq, this query is working but i need to get the sum of Amount where dlist.TransTypeID == 0 and where dlist.TransTypeID == 1 by just single query. may anybody help me? thanks in advance
Here's a trimmed down example of how you can do it. You can add the joins if they are necessary, but I'm not clear on why you need some of the extra join values.
var transTypeAmountSums = (from dlist in db.DebtorTransactions
group dlist by dlist.TransTypeId into g
where g.Key == 0 || g.Key == 1
select new
{
TransTypeId = g.Key,
AmountSum = g.Sum(d => d.Amount)
}).ToDictionary(k => k.TransTypeId, v => v.AmountSum);
int transTypeZeroSum = transTypeAmountSums[0];
int transTypeOneSum = transTypeAmountSums[1];
A couple of things to note:
I removed ToList(). Unless you want to bring ALL DebtorTransactions into memory then run a Linq operation on those results, you'll want to leave that out and let SQL take care of the aggregation (it's much better at it than C#).
I grouped by dlist.TransTypeId only. You can still group by more fields if you need that, but it was unclear in the example why they were needed so I just made a simplified example.

In join want to get not matched records

Work on DF 4 vs 2010.Face problem on join on SalSalesOrderDetail with SalSalesOrderFinancial table.
In SalSalesOrderFinancial one record have SalesOrderDetailID=null. Want to get those records whose SalesOrderDetailID is not present in SalSalesOrderFinancial.
To get desired out put write bellow linq syntax,it’s working .Looking for better join syntax .Is there any way to get desired in one join.
var tempBDwithSODetail = (from p in this.Context.SalSalesOrderFinancials
where p.SalesOrderDetailID != null
select p.SalesOrderDetailID).AsEnumerable();
var tempBDwithOutSODetail = (from p in this.Context.SalSalesOrderFinancials where p.SalesOrderDetailID == null select p).AsEnumerable();
var querySOD = (this.Context.SalSalesOrderDetails.Where(item => !tempBDwithSODetail.Contains(item.SalesOrderDetailID))).AsEnumerable();
var tempBDetail = (from p in querySOD
join q in tempBDwithOutSODetail on p.SalesOrderID equals q.SalesOrderID
where q.SalesOrderDetailID == null
select new
{
q.SalesOrderID,
p.SalesOrderDetailID,
q.CurrencyID,
q.BillingPolicyID,
q.BillTypeID,
q.BillingTypeID
}).AsEnumerable();
If have any query please ask.Thanks in advanced.
if i got you, you just need to simple left join between SalSalesOrderDetail and SalSalesOrderFinancial...
var query = (from u in this.Context.SalSalesOrderDetail
join t in this.Context.SalSalesOrderFinancials
on u.SalesOrderDetailID equals t.SalesOrderDetailID into JoinedList
from t in JoinedList.DefaultIfEmpty()
select new
{
SalSalesOrderDetail = t,
SalSalesOrderFinancials = u
})
.Where(u => u.SalSalesOrderFinancials == null)
.ToList();

How to write this Linq Query in a better way to return the sum

I have one LINQ query. In that I need to do some calculations. Everything is fine except when null value found in the either one condition then simply it returns null for the whole condition. Can anyone tell me how can i return the some value even there is a null value found in the condition.
Code
var model =
(from q in db.Porders
select new porders()
{
Id = q.Id,
DetCount = (from amtdet in db.PoDetails
where amtdet.PoId == q.Id
select amtdet.Id).Count(),
Amount = (from amtpord in db.Porders
where amtpord.Id == q.Id
select amtpord.Freight + amtpord.Misc - amtpord.Discount
).FirstOrDefault() +
(from amtdet in db.PoDetails
where amtdet.PoId == q.Id
select amtdet.Copies * amtdet.EstUnitPrice
).Sum()
}).ToList();
I think the DefaultIfEmpty() method will be the solution here
var model =
from q in db.Porders
select new porders()
{
DetCount =
db.PoDetails.Count(amtdet => amtdet.PoId == q.Id),
Amount =
(from amtpord in db.Porders
where amtpord.Id == q.Id
select amtpord.Freight + amtpord.Misc - amtpord.Discount)
.DefaultIfEmpty().First()
+
(from amtdet in db.PoDetails
where amtdet.PoId == q.Id
select amtdet.Copies * amtdet.EstUnitPrice)
.DefaultIfEmpty().Sum()
}
Try applying coalescing column ?? 0 operator on nullable columns or on the result of the FirstOrDefault (for the case that condition is not met). Linq to entities will turn this operator into SQL:
CASE WHEN Column IS NOT NULL THEN Column ELSE 0 END
It will look like:
var model =
(from q in db.Porders
select new porders()
{
Id = q.Id,
Amount = (from amtpord in db.Porders
where amtpord.Id == q.Id
select amtpord.Freight ?? 0 + amtpord.Misc ?? 0 - amtpord.Discount ?? 0
).FirstOrDefault() ?? 0 +
(from amtdet in db.PoDetails
where amtdet.PoId == q.Id
select amtdet.Copies ?? 0 * amtdet.EstUnitPrice ?? 0
).Sum() ?? 0
}).ToList();
Let me first assume that there is a navigation property Porder.Details. Next, why do you select the same Porder in a sub query? It seems to me that your query can be simplified as
from q in db.Porders
select new porders()
{
Id = q.Id,
DetCount = q.Details.Count(),
Amount = q.Freight + q.Misc - q.Discount
+ q.PoDetails.Select( d => d.Copies * d.EstUnitPrice)
.DefaultIfEmpty().Sum()
}
If there isn't such a navigation property it is highly recommended to create one. If you can't or don't want to do that for whatever reason, you should group join the detail records in the main query (db.Porders.GroupJoin(db.PoDetails...)).
If the null values are caused by Freight, Misc or Discount to be nullable, use ?? operator: q.Freight ?? 0.

Resources