How to linq join if datatable doesn't have all the rows - c#

I'm having an issue where I'm getting nothing back. Here is my code:
var final = (from table1 in dtS.AsEnumerable()
join table2 in DataDT.AsEnumerable()
on table1.Field<string>(1) equals table2.Field<string>(0)
join table3 in DataDT2.AsEnumerable()
on table1.Field<string>(1) equals table3.Field<string>(0)
join table4 in DataDT3.AsEnumerable()
on table1.Field<string>(1) equals table4.Field<string>(0)
select new Model
{
TestID = table1.Field<int>(0),
ID = table1.Field<string>(1),
Name = table1.Field<string>(2),
Absent = table1.Field<bool>(3),
Gender = table1.Field<string>(4),
Grade = table1.Field<int>(5),
TestDate = table1.Field<string>(7),
SessionNumber = table1.Field<int>(8),
Room = table1.Field<string>(9),
Code = table1.Field<string>(10),
Booklet = table1.Field<string>(11),
Color = table4.Field<string>(3),
Accomm = table3.Field<string>(1),
SID = table2.Field<string>(1),
LocalName = table2.Field<string>(2)
}).ToList();
If I comment out the last two joins and "Color, Accomm, SID and Local" . I seem to get all of my info.
table1 has 300 rows. This has all the people
table2 has 1000 rows. Has some extra data I need to add
table3 has 10. Has some extra data that I need to add (but doesn't have everyone)
table4 has 17. Has some extra data that I need to add (but doesn't have everyone)
Doesn't seem to "Linq" up (drums). Thanks for the help. I know I'm over thinking something..

Thanks to #Marcus Hoglund for pointing out the outer join. I was able to make some changes and it's working.
Here you go:
var final = (from studData in dtS.AsEnumerable()
join table2 in DataDT.AsEnumerable() on studData[1] equals table2[0] into part1
from p1 in part1.DefaultIfEmpty()
join table3 in DataDT2.AsEnumerable() on studData[1] equals table3.Field<string>(0) into part2
from p2 in part2.DefaultIfEmpty()
join table4 in DataDT3.AsEnumerable() on studData[1] equals table4.Field<string>(0) into part3
from p3 in part3.DefaultIfEmpty()
select new Model
{
TestID = table1.Field<int>(0),
ID = table1.Field<string>(1),
Name = table1.Field<string>(2),
Absent = table1.Field<bool>(3),
Gender = table1.Field<string>(4),
Grade = table1.Field<int>(5),
TestDate = table1.Field<string>(7),
SessionNumber = table1.Field<int>(8),
Room = table1.Field<string>(9),
Code = table1.Field<string>(10),
Booklet = table1.Field<string>(11),
Color = (p3 == null) ? "" : p3[1],
Accomm = (p2 == null) ? "" : p2[1],
SID = (p1 == null) ? "" : p1[1],
LocalName = (p1 == null) ? "" : p1[2],
}).ToList();

Related

LEFT JOIN query with Entity Framework Core

I did a lot of research and read some of the similar questions and answers, but still have no clue how to write the EF Core code to create the following SQL server query. Can someone help. I have seen tutorials explaining how to join 2 tables with LEFT JOIN, but couldn't find any that includes 3 or more tables.
SELECT std.DocID, std.ServiceCode,
CASE std.Description
WHEN 'Car Wash'
THEN 'Misc'
ELSE std.Description
END AS 'Description',
std.StandardRate, std.StandardHours,
det.ParticipantCount, det.TotalHours, det.TotalFees
FROM StandardServices std
INNER JOIN Sorted srt
ON std.ServiceCode = srt.ServiceCode
LEFT OUTER JOIN ServiceDetails det
ON det.ParentRecordUNID='00000000-0000-0000-0000-000000000000' AND det.ServiceTypeUNID=std.DocID
WHERE std.IsDeleted='N' AND std.TopService = 'Y'
ORDER BY srt.SortOrder
Following is what came close to the above (I have replaced some text for privacy concerns, so may not exactly match). But for some reasons, it selects all of the columns than what is mentioned. Also, it adds a (SELECT 1) at the end.
var results=await (from sso in context.StandardServices
join mos in context.Sorted on sso.ServiceCode equals mos.ServiceCode
join mad in context.ServiceDetails
on new { key1 = sso.DocID, key2 = parentId } equals new { key1 = (Guid)mad.ServiceTypeUnid, key2 = mad.ParentRecordUnid }
into jointable
where sso.IsDeleted == "N" && sso.TopService =="Y"
orderby mos.SortOrder
from mad1 in jointable.DefaultIfEmpty()
select new ServiceRowDetails()
{
DocID = mad1.DocID,
ParentRecordUnid = mad1.ParentRecordUnid,
ServiceTypeUnid = sso.DocID,
ServiceType = sso.Description,
ParticipantCount = mad1.ParticipantCount ?? 0,
StandardFees = sso.StandardRate ?? 0,
StandardHours = sso.StandardHours ?? 0,
TotalFees = mad1.TotalFees ?? 0,
TotalHours = mad1.TotalHours ?? 0
}).ToListAsync();
UPDATE: Made changes as #IvanStoev commented below and it worked just fine.
var results=await (from sso in context.StandardServices
join mos in context.Sorted on sso.ServiceCode equals mos.ServiceCode
join mad in context.ServiceDetails
on new { key1 = sso.DocID, key2 = parentId } equals new { key1 = (Guid)mad.ServiceTypeUnid, key2 = mad.ParentRecordUnid }
into jointable
from mad1 in jointable.DefaultIfEmpty()
where sso.IsDeleted == "N" && sso.TopService =="Y"
orderby mos.SortOrder
select new ServiceRowDetails()
{
DocID = mad1.DocID,
ParentRecordUnid = mad1.ParentRecordUnid,
ServiceTypeUnid = sso.DocID,
ServiceType = sso.Description,
ParticipantCount = mad1.ParticipantCount ?? 0,
StandardFees = sso.StandardRate ?? 0,
StandardHours = sso.StandardHours ?? 0,
TotalFees = mad1.TotalFees ?? 0,
TotalHours = mad1.TotalHours ?? 0
}).ToListAsync();

Trying to add item to linq select statement in c#

I have a long result set in linq which is put in ratestest, I am mapping the result to ChargeElementsNullable. The issue is this doesnt include a fee record which is
var fees = (from r in _dbContext.Rates
where r.RateTypeFK == RateType.Fee && (r.LocaleBW & localeid) > 0 && (r.PolicyBW & policy.BitWise) > 0 && r.RateExclude == 0
select r);
So I want to add fees to ratestest and I could do that mapping again so I can use the add method, but I dont want to do that long winded mapping just for one record.. I am trying to add it to ratestest directly instead.. but no joy... I tried using DefaultIfEmpty expecting a left join.. but fee still wasnt in there..
var ratestest = (from qi in quoteInputs
join r in _dbContext.Rates on qi.RatePK equals r.RatePK
join fee in fees on r.RatePK equals fee.RatePK into feecontainer
from fee in feecontainer.DefaultIfEmpty()
join c in _dbContext.Covers on r.CoverCalcFK equals c.CoverPK into covers
from c in covers.DefaultIfEmpty()
join rt in _dbContext.RateTypes on qi.RateTypeFK equals rt.RateTypePK
where rt.Ratable == 1 ||
rt.RateTypePK == RateType.PostCode ||
rt.RateTypePK == RateType.Fee// employersliab.Contains(r.InputFK)
select new ChargeElementsNullable
{
PolicyFK = quote.PolicyFK,
InputFK = r.InputFK,
LongRate = r.LongRate,
RateLabel = r.RateLabel,
CoverName = c.CoverName,
CoverFK = r.CoverCalcFK,
CoverBW = c.BitWise,
ListRatePK = r.ListRatePK,
RatePK = r.RatePK,
RateName = r.RateName,
Rate = r.Rate,
Threshold = r.Threshold,
Excess = r.Excess,
DivBy = r.DivBy,
DiscountFirstRate = r.DiscountFirstRate,
DiscountSubsequentRate = r.DiscountSubsequentRate,
HazardRating = r.HazardRating,
TableFirstColumn = r.TableFirstColumn,
TableChildren = r.TableChildren,
RateTypeFK = r.RateTypeFK,
PageNo = r.PageNo,
SumInsured = qi.SumInsured,
NoItems = qi.NoItems,
RateValue = qi.RateValue,
TriggerCode = rt.TriggerCode,
Territory = territory
}).ToList();
You have to create a model with two properties one for quoteInputs and another for fees. Then you just need to select both of them.
Eg:
class model1
{
public QuoteInputs quoteInputs {get;set;}
public Fees fees{get;set;}
}
Then you call use this model in the select clause and assign this model tables directly.
Now let's take your code and change select like this :
var ratestest = (from qi in quoteInputs
join r in _dbContext.Rates on qi.RatePK equals r.RatePK
join fee in fees on r.RatePK equals fee.RatePK into feecontainer
from fee in feecontainer.DefaultIfEmpty()
join c in _dbContext.Covers on r.CoverCalcFK equals c.CoverPK into covers
from c in covers.DefaultIfEmpty()
join rt in _dbContext.RateTypes on qi.RateTypeFK equals rt.RateTypePK
where rt.Ratable == 1 ||
rt.RateTypePK == RateType.PostCode ||
rt.RateTypePK == RateType.Fee// employersliab.Contains(r.InputFK)
select new model1{
quoteInputs = qi,
fees = fee
}).ToList();
As you mentioned in comments, you are seeking for Concat method (MSDN). This can be done like this:
var fees = from ...
select new ChargeElementsNullable {
Prop1 = (some value),
Prop2 = (other value)
}
var ratestest = from ...
select new ChargeElementsNullable {
Prop1 = (some value),
Prop2 = (other value)
}
var bothtogether = fees.Concat(ratestest);
Be sure, that you have all properties in exactly same order and all properties are in both selects. Otherwise Linq2Sql will fail when obtaining results. (I assume from your code that you are using it)
As #Cris correctly pointed out in comments, same order is not necessary.

Left outer join of 2 datatables

I want to left join 2 data tables AllTimesTxnTable and resolvedDt in C#, Where I want every row from AllTimesTxnTable and only matching rows from resolvedDt.
The join condition should be based on mid and txndate and finally while selecting I want mid and txndate from AllTimesTxnTable and txncount from resolvedDt, if no record in resolvedDt then a 0.
I tried the following LINQ query:
var results = from table2 in AllTimesTxnTable.AsEnumerable()
join table1 in resolvedDt.AsEnumerable()
on new { mid = table2.Field<int>("mid"), txndate = table2.Field<string>("txndate") } equals new { mid = table1.Field<int>("mid"), txndate = table1.Field<string>("txndate") }
into temp
from leftTable in temp.DefaultIfEmpty()
select new
{
MId = (int)table2["mid"],
TxnDate = (string)table2["txndate"],
TxnCount = leftTable["txncount"] == null ? 0M : (decimal)leftTable["txncount"]
};
But it gives me an Error: Object reference not set to an instance of an object. while selecting.
Not getting whats going wrong here.
Updated the code. Its working now.
var results = from table2 in AllTimesTxnTable.AsEnumerable()
join table1 in resolvedDt.AsEnumerable()
on new { mid = table2.Field<int>("mid"), txndate = table2.Field<string>("txndate") } equals new { mid = table1.Field<int>("mid"), txndate = table1.Field<string>("txndate") }
into temp
from row in temp.DefaultIfEmpty()
select new
{
MId = (int)table2["mid"],
TxnDate = (string)table2["txndate"],
TxnCount = row == null ? 0M : (decimal)row["txncount"]
};

How to write Outer Join using LINQ

I am using the below Inner Join to retrive the Data between the two tables, but all data is not getting populated. I tried implementing Outer join by connecting using CCY1== CCY1 and PCODE == PCODE, but no luck.
var q = from g1 in TableCCY1.AsEnumerable()
join g2 in TableCCY2.AsEnumerable()
on g1.Field<string>("CCY1") equals g2.Field<string>("CCY1")
where g1.Field<string>("PCODE") == g2.Field<string>("PCODE")
select new
{
g1currency = g1.Field<string>("CCY1"),
g2currency = g2.Field<string>("CCY1"),
g1code = g1.Field<string>("PCODE"),
g2code = g2.Field<string>("PCODE"),
g1Amt1 = g1.Field<string>("AMT1"),
g2Amt2 = g2.Field<string>("AMT2")
};
Thanks for your help.
For left join you can use this approuch: http://msdn.microsoft.com/en-us/library/vstudio/bb397895.aspx
The code should be:
var q = from g1 in TableCCY1
join g2 in TableCCY2 on g1.CCY1 equals g2.CCY1 && g1.PCODE equals g2.PCODE into TableCCY3
from g3 in TableCCY3.DefaultIfEmpty()
select new
{
g1currency = g1.CCY1,
g2currency = (g3 == null ? String.Empty : g3.CCY1),
g1code = g1.PCODE,
g2code = (g3 == null ? String.Empty : g3.PCODE),
g1Amt1 = g1.AMT1,
g2Amt2 = (g3 == null ? 0 : g3.AMT2)
};
It looks like you just want to union/concat the two tables into one and then just group on those two columns. You're not logically joining the two tables. That actually makes it much easier.
var q = from row in TableCCY1.AsEnumerable().Concat(TableCCY2.AsEnumerable())
group row by new
{
CCY1 = row.Field<string>("CCY1"),
PCode = row.Field<string>("PCODE")
} into matches
select new
{
CCY1 = matches.Key.CCY1,
PCODE = matches.Key.PCode,
Sum = matches.Sum(match => match.Field<decimal?>("AMT2")),
};

sql to linq statement with left join, group by and with case statement

Im just new in MVC3 and have a little problem. I want to convert this SQL statement into Linq. Can anyone please help me with this problem, here is my sql Statement:
SELECT a.payment_ref_no,
c.institution_name,
a.check_date,
batchstatus = CASE
WHEN d.mccount = Count(b.check_detail_no) THEN
'Completed'
WHEN d.mccount IS NULL THEN 'Approved'
WHEN d.mccount < Count(b.check_detail_no) THEN
'Partially Processed'
END,
noofpayments=Count(b.check_detail_no),
totalamount=Sum(b.check_amount),
d.mccount
FROM check_request a
JOIN check_details b
ON a.request_ref_no = b.request_ref_no
JOIN institution c
ON a.company_code = c.company_code
LEFT JOIN vw_batchstatus d
ON a.request_ref_no = d.request_ref_no
WHERE a.payment_ref_no IS NOT NULL
GROUP BY a.payment_ref_no,
a.check_date,
c.institution_name,
d.mccount
Done mostly from memory, may be some issues, but should be a step in the right direction for you.
var test = from a in check_request
join b in check_details on a.request_ref_no equals b.request_ref_no
join c in institution on a.company_code equals c.company_code
join d in vw_batchstatus on a.request_ref_no equals d.request_ref_no into dvwinner
from d in dvwinner.DefaultIfEmpty()
where a.payment_ref.HasValue
group a by new (a.payment_ref_no, a.check_date, c.institution_name, d.mccount) into gr1
select new {
ref_no = a.payment_ref_no,
inst_name = c.institution_name,
check_date = a.check_date,
batstat = !d.mccount.HasValue ? 'Approved' : d.mccount == b.check_detail_no.Count() ? 'Completed' : 'Partially Processed',
noofpayments = b.check_detail_no.Count(),
ttlamount = gr1.Sum(p=>p.check_amount),
mccount = d.mccount
};
Thanks Kyle for the help.I finally solved my own problems, here is the linq of my sql statement
var test = from a in CHECK_REQUESTs
join b in CHECK_DETAILS on a.REQUEST_REF_NO equals b.REQUEST_REF_NO
join c in INSTITUTIONs on a.COMPANY_CODE equals c.COMPANY_CODE
join d in Vw_BatchStatus on a.REQUEST_REF_NO equals d.REQUEST_REF_NO into t from rt in t.DefaultIfEmpty()
where a.PAYMENT_REF_NO != string.Empty
let institutionName = (string)c.Institution_Name
let mcCount = (int)rt.Mccount
group b by new
{
a.PAYMENT_REF_NO,
a.Check_Date,
institutionName,
mcCount
} into gr1
select new
{
gr1.Key.PAYMENT_REF_NO,
gr1.Key.institutionName,
gr1.Key.Check_Date,
batchstatus = (gr1.Key.mcCount == gr1.Count()) ? "Completed" :
(gr1.Key.mcCount < gr1.Count()) ? "Partially Processed":
(gr1.Key.mcCount == null ) ? "Approved" : " ",
noofpayments = gr1.Count(),
totalamount = gr1.Sum(c => c.Check_Amount)
};

Categories

Resources