How to write Outer Join using LINQ - c#

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")),
};

Related

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

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

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.

Converting an SQL Containing inner and Outer Joins into Linq

I need to convert an SQL query to Linq/Lambda expression, I am trying doing the same but not getting the desired results.
SQL:
SELECT b.*, n.notes
FROM Goal_Allocation_Branch as b
INNER JOIN Goal_Allocation_Product as g
on b.Product = g.ProductID
and b.Year = g.Year
left join Goal_Allocation_Branch_Notes as n
on b.branchnumber = n.branch
and n.year = ddlYear
WHERE b.Year = ddlYear
and g.Show = 1
and branchnumber = ddlBranch
I am new to Linq , I am getting error on Join Clause , and X is not containing any data from first Join
var result = (from br in _DB_Branches.Goal_Allocation_Branches
join pr in _DB_Product.Goal_Allocation_Products on new { br.Product, br.Year } equals new {Product= pr.ProductID, Year= pr.Year }
join n in _DB_Notes.Goal_Allocation_Branch_Notes.Where(n => n.Year == ddlYear) on br.BranchNumber equals n.Branch into Notes
from x in Notes.DefaultIfEmpty()
select new BranchNotesViewModel
{
Year = x.Year,
BranchNumber = x.Branch,
ProductID = x.ProdID
}
).ToList();
Update: My First Join clause initially giving error "The type of one of the expression in Join Clause is incorrect " is resolved, when I Changed On Clause
from
"on new { br.Product, br.Year } equals new {pr.ProductID, pr.Year}"
"on new { br.Product, br.Year } equals new {Product=pr.ProductID,Year= pr.Year}"
still not getting desired results as expected from above SQL query. Please advise..
It should be something like this (see note):
var result =
(from br in _DB_Branches.Goal_Allocation_Branches
join pr in _DB_Product.Goal_Allocation_Products
on br.Product equals pr.ProductID
from n in _DB_Notes.Goal_Allocation_Branch_Notes.Where(x=>
x.branch == br.branchnumber
&& x.year == ddlYear
).DefaultIfEmpty()
where
br.Year == ddlYear
&& and br.Year == pr.Year
&& pr.Show == 1
&& br.branchnumber == ddlBranch
select new BranchNotesViewModel
{
Year = ...,
BranchNumber = ...,
ProductID = ...
}
).ToList();
Note: Change the select, to the properties you want.
Edit: fixed some syntax errors.
I finally figured out the correct answer. Working absolutely fine
var result = (from br in _DB_Branches.Goal_Allocation_Branches
join pr in _DB_Product.Goal_Allocation_Products on new { br.Product, br.Year } equals new { Product = pr.ProductID, Year = pr.Year }
join n in _DB_Notes.Goal_Allocation_Branch_Notes.Where(n=>n.Year==ddlYear) on br.BranchNumber equals n.Branch into Notes
where br.Year==ddlYear
&& pr.Show== true
&& br.BranchNumber==ddlBranch
from x in Notes.DefaultIfEmpty()
select new BranchNotesViewModel
{
Year=x.Year,
BranchNumber=x.Branch,
ProductID=br.Product,
Notes = x.Notes,
//All other fields needed
}
).ToList();

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

Entity Framework - Results from subquery, speed issue?

I've made a query to get a list of articles, each bound to a "header",
so i retrieve the header plus the related articles and their properties.
The query works, however in its current style it is
Somewhat messy ( in my opinion)
The .ToList() takes way longer than i would expect.
Does anyone see any obvious reason for the speed-issue?
var offerheaders =
from o in dbcontext.F_CAB_OFFER_HEADERS
where
o.OFHD_FK_BUYER == userinfo.orgaTypeSequence
&& o.OFHD_VALID_FROM <= userinfo.selectedDate
&& o.OFHD_VALID_TO >= userinfo.selectedDate
&& o.OFHD_DELETED_YN == 0
&& o.OFHD_DELETED_BY_OWNER_YN == false
&& o.OFHD_OFFER_TYPE == userinfo.offerType
orderby o.OFHD_NO ascending
select o;
var offerlist =
from ofhd in offerheaders
select new {
ofhd = new {
OfferNo = ofhd.OFHD_NO,
OfferSequence = ofhd.OFHD_SEQUENCE,
ValidFrom = ofhd.OFHD_VALID_FROM,
ValidTo = ofhd.OFHD_VALID_TO,
OfferType = ofhd.OFHD_OFFER_TYPE,
Maingroup = new { cdmg_seq = ofhd.F_CAB_CD_MAIN_GROUP_TYPE.CDMG_SEQUENCE, Desc = ofhd.F_CAB_CD_MAIN_GROUP_TYPE.CDMG_DESC },
Supplier = new {
Name = ofhd.F_CAB_GROWER.F_CAB_ORGANISATION.ORGA_NAME,
Pic = ofhd.F_CAB_GROWER.F_CAB_ORGANISATION.ORGA_FK_PICTURE,
Seq = ofhd.F_CAB_GROWER.GROW_SEQUENCE
},
Caption = ofhd.OFHD_CAPTION,
Seperate = ofhd.OFHD_SHOW_SEPARATE_YN,
//ofdts = (from ofdt in dbcontext.F_CAB_OFFER_DETAILS.Where(x => x.OFDT_FK_OFFER_HEADER == ofhd.OFHD_SEQUENCE && x.OFDT_NUM_OF_ITEMS > 0 && x.OFDT_LATEST_DELIVERY_DATE_TIME > compareDateTime && x.OFDT_LATEST_ORDER_DATE_TIME > compareDateTime)
ofdts = from ofdt in dbcontext.F_CAB_OFFER_DETAILS
join props in dbcontext.F_CAB_CAB_PROP on ofdt.OFDT_FK_CAB_CODE equals props.PROP_FK_CABC_SEQ
join cabcode in dbcontext.F_CAB_CD_CAB_CODE on ofdt.OFDT_FK_CAB_CODE equals cabcode.CABC_SEQUENCE
join cabgroup in dbcontext.F_CAB_CD_CAB_GROUP on cabcode.CABC_FK_CAB_GROUP equals cabgroup.CDGR_SEQUENCE
join grouptype in dbcontext.F_CAB_CD_GROUP_TYPE on cabgroup.CDGR_FK_GROUP_TYPE equals grouptype.CDGT_SEQUENCE
join maingrouptype in dbcontext.F_CAB_CD_MAIN_GROUP_TYPE on grouptype.CDGT_FK_MAIN_GROUP equals maingrouptype.CDMG_SEQUENCE
join caca in dbcontext.F_CAB_CAB_CASK_MATRIX on ofdt.OFDT_FK_CACA_SEQ equals caca.CACA_SEQUENCE
join cask in dbcontext.F_CAB_CD_CASK on caca.CACA_FK_CASK equals cask.CDCA_SEQUENCE
join vbncode in dbcontext.F_CAB_CAB_VBN_MATRIX on cabcode.CABC_SEQUENCE equals vbncode.CVMA_FK_CAB_CODE
join grel in dbcontext.F_CAB_GENERAL_RELATIONS on ofdt.OFDT_FK_GREL_SEQ equals grel.GREL_SEQUENCE into greltable
from g_loj in greltable.DefaultIfEmpty()
where
ofdt.OFDT_FK_OFFER_HEADER == ofhd.OFHD_SEQUENCE
&& ofdt.OFDT_NUM_OF_ITEMS > 0
&& props.PROP_FK_CDLA_SEQ == userinfo.lang.CDLA_SEQUENCE
orderby props.PROP_CAB_DESC ascending
select new {
Desc = props.PROP_CAB_DESC,
Group = new { cdgr_seq = cabgroup.CDGR_SEQUENCE, Desc = cabgroup.CDGR_DESC },
Grouptype = new { grouptype.CDGT_SEQUENCE, Desc = grouptype.CDGT_DESC },
Properties = new CABProperties { props = props },
Price = ofdt.OFDT_ITEM_PRICE,
PIC_SEQ = ofdt.OFDT_FK_PICTURE ?? ((cabcode.CABC_FK_PICTURE ?? cabcode.CABC_SEQUENCE)),
PIC_URL = ofdt.OFDT_EXT_PICTURE_REF ?? "",
Seq = ofdt.OFDT_SEQUENCE,
Available = ofdt.OFDT_NUM_OF_ITEMS,
CabCode = ofdt.F_CAB_CD_CAB_CODE.CABC_CAB_CODE,
VBNCode = vbncode.CVMA_FK_VBN_CODE,
Remark = ofdt.OFDT_REMARK,
IsSpecial = ofdt.OFDT_SPECIAL_YN,
Arrived = inTransit ? ofdt.OFDT_ARRIVAL_DATE < DateTime.Now : true,
Cask = new CABCask { cask = cask, caca = caca },
Supplier = g_loj == null ? (ofdt.OFDT_SUPPLIER ?? "") : g_loj.GREL_NAME,
SupplierWeb = g_loj == null ? "" : g_loj.GREL_WEBSITE_URL,
SupplierLogo = g_loj == null ? ofhd.F_CAB_GROWER.F_CAB_ORGANISATION.ORGA_FK_PICTURE : g_loj.GREL_FK_PICT_SEQ,
SupplierSeq = g_loj == null ? -1 : g_loj.GREL_SEQUENCE,
}
}
};
userinfo.mainofferlist = offerlist.ToList();
As Daniel Kelly also mentioned the ToList function is where your query is executed, because these LinqToEntities queries are executed at the point where they are first enumerated, and ToList does that to be able to create a list.
Basically the reason why your querying takes so much time can be separated into two different reasons:
you are using too much projections and I thine (the parts with new {
})
your query has an incredible amount of join clauses
I would recommend to separate your query into subqueries, and run them separately like the first part in
...
select o
use
...
select o).ToList()
by breaking down the main query where you have a lot of subqueries it will be faster and much more readable, so you have less "messiness".
And last but not least you should create mapping for the anonymous objects, and use those classes other than projection that should speed up your query.

Categories

Resources