SQL to Linq: left join - c#

I need to write linq query. I tried to write example in sql and it works great but I didn't manage to convert it to proper linq
This is my working sql query:
SELECT
pr.descr as product,
prm.Descr
, px.Value AS ParamValue
, prm.Unit AS Unit
, gx.TcPos
FROM [Product] pr
JOIN [PrGroup] prg ON pr.GroupId = prg.Id
LEFT JOIN [PrParamGroup] pg ON ISNULL(pr.PrParamGroupId, prg.PrParamGroupId) = pg.Id
CROSS JOIN [PrParam] prm
LEFT JOIN [PrParam2ProductX] px ON pr.Id = px.ProductId AND prm.Id = px.PrParamId
LEFT JOIN [PrParam2GroupX] gx ON prm.Id = gx.PrParamId AND pg.Id = gx.PrParamGroupId
WHERE
pr.Id = 123 AND
(px.PrParamId IS NOT NULL OR gx.PrParamId IS NOT NULL)
AND (gx.PrParamId <> -1 OR gx.PrParamId IS NULL)
AND (gx.PrParamId IS NOT NULL)
This is my linq attempt:
var productsDesc = (from pr in context.Product.Where(m => m.Id == 123)
join prg in context.PrGroup
on pr.GroupId equals prg.Id
join pg in context.PrParamGroup
on pr.PrParamGroupId equals pg.Id
from prm in context.PrParam
join px in context.PrParam2ProductX
on new { a = pr.Id, b = px.ProductId } equals new { a = prm.Id, b = px.PrParamId }
join gx in context.PrParam2GroupX
on new { prm.Id = gx.PrParamId } equals new { pg.Id = gx.PrParamGroupId }
select new
{
Name = prm.Descr,
Value = px.Value,
Unit = prm.Unit ?? ""
}).ToList();

Your linq dont implement left join and cross join
try this
var productsDesc = (from pr in context.Product.Where(m => m.Id == 123)
join prg in context.PrGroup
on pr.GroupId equals prg.Id
join pg in context.PrParamGroup
on pr.PrParamGroupId equals pg.Id into tmp1
from t1 in tmp1.DefaultIfEmpty()
from prm in context.PrParam
join px in context.PrParam2ProductX
on new { a = pr.Id, b = px.ProductId } equals new { a = prm.Id, b = px.PrParamId } into tmp2
from t2 in tmp2.DefaultIfEmpty()
join gx in context.PrParam2GroupX
on new { prm.Id = gx.PrParamId } equals new { pg.Id = gx.PrParamGroupId } into tmp3
from t3 in tmp3.DefaultIfEmpty()
select new
{
Name = prm.Descr,
Value = t2.Value,
Unit = prm.Unit ?? ""
}).ToList();

Related

Pass parameters to linq queries

I have the following part of code that works perfectly.
public Task<List<RsvItemsViewModel>> GetReservations(int company_ID)
{
try
{
// we cannot pass parameter as company_id . we use hard coded values as 1 for CompanyId.Must find a way to overcome this
return ((from a in gTravelDbContext.Set<Frsvitem>()
join d in gTravelDbContext.Set<Freserv>()
on a.Rsinum equals d.Rsvnum into gd from d in gd.Where(p1 => p1.CompanyId == 1)
join c in gTravelDbContext.Set<Fsupplier>()
on a.SupplId equals c.SupplId into gc from c in gc.Where(p1=>p1.CompanyId == 1)
join i in gTravelDbContext.Set<Fzone>()
on a.Rsizone equals i.Zoneid into gi
from i in gi.DefaultIfEmpty() where i.CompanyId == 1
join g in gTravelDbContext.Set<Fservtype>()
on a.Rsisertype equals g.Stypecode
join b in gTravelDbContext.Set<Fcustomer>()
on d.CustId equals b.CustId
join e in gTravelDbContext.Set<Fpaykind>()
on d.Rsvpaymethod equals e.Payid into ge
from e in ge.DefaultIfEmpty()
join f in gTravelDbContext.Set<Fsalesman>()
on d.Rsvsalescode equals f.Salescode into gf
from f in gf.DefaultIfEmpty()
join h in gTravelDbContext.Set<Fpinake>()
on d.Rsvakirosi equals h.Tblid into gh
from h in gh.Where(p => p.Tblcd == "yesno")
select new RsvItemsViewModel
{
Rsinum = a.Rsinum,
Stypename = g.Stypename,
Cuname = b.Cuname,
Rsvcuname = d.Rsvcuname,
Sumame = c.Suname,
Rsvakirosi = d.Rsvakirosi,
Yesno = h.Tbltext ,
Paytext = e.Paytext,
Salesname = f.Salesname,
Stypegroup = g.Stypegroup,
Company_id =d.CompanyId.GetValueOrDefault(),
Zonename = i.Zonename,
Rsisertype = a.Rsisertype,
Suppl_id = a.SupplId,
Xrhsh = d.Xrhsh,
Bpar_id = a.BparId
}
).ToListAsync());
}
catch (Exception)
{
throw;
}
}
The problem is that I want to pass company_ID as a parameter in linq and I want to substitute the Where(p1 => p1.CompanyId == 1) with Where(p1 => p1.CompanyId == company_ID )
I would be grateful if someone could help me.
Thank you
You have used GroupJoin in way, which is not supported by EF Core. GroupJoin has a lot of limitations and use it only if you need LEFT JOIN.
I have rewritten your query to be translatable:
var query =
from a in gTravelDbContext.Set<Frsvitem>()
from d in gTravelDbContext.Set<Freserv>().Where(d => d.Rsvnum == a.Rsinum && d.CompanyId == company_ID)
from c in gTravelDbContext.Set<Fsupplier>().Where(c => a.SupplId == c.SupplId && c.CompanyId == company_ID)
from i in gTravelDbContext.Set<Fzone>().Where(i => a.Rsizone == i.Zoneid && c.CompanyId == company_ID).DefaultIfEmpty()
join g in gTravelDbContext.Set<Fservtype>()
on a.Rsisertype equals g.Stypecode
join b in gTravelDbContext.Set<Fcustomer>()
on d.CustId equals b.CustId
join e in gTravelDbContext.Set<Fpaykind>()
on d.Rsvpaymethod equals e.Payid into ge
from e in ge.DefaultIfEmpty()
join f in gTravelDbContext.Set<Fsalesman>()
on d.Rsvsalescode equals f.Salescode into gf
from f in gf.DefaultIfEmpty()
from h in gTravelDbContext.Set<Fpinake>().Where(h => d.Rsvakirosi == h.Tblid && h.Tblcd == "yesno")
select new RsvItemsViewModel
{
Rsinum = a.Rsinum,
Stypename = g.Stypename,
Cuname = b.Cuname,
Rsvcuname = d.Rsvcuname,
Sumame = c.Suname,
Rsvakirosi = d.Rsvakirosi,
Yesno = h.Tbltext ,
Paytext = e.Paytext,
Salesname = f.Salesname,
Stypegroup = g.Stypegroup,
Company_id =d.CompanyId.GetValueOrDefault(),
Zonename = i.Zonename,
Rsisertype = a.Rsisertype,
Suppl_id = a.SupplId,
Xrhsh = d.Xrhsh,
Bpar_id = a.BparId
}

The specified LINQ expression contains references to queries that are associated with different contexts c#

I have this simple function that returns a query, but when I try to join 2 tables in different databases, the error raised: The specified LINQ expression contains references to queries that are associated with different contexts.
here is my code.
private object projectcycleFilter(int? pid, int? cid, int UserId)
{
string[] res = { null, "" };
int?[] resint = { null, 0 };
var access_user = (from p in geotagging.webpages_UsersInRoles join s in geotagging.UserProfiles on p.UserId equals s.UserId where p.UserId == UserId select p).ToList();
var x = new object();
var geotaggingquery = (from xx in geotagging.sub_project select xx).AsEnumerable();
var nfmsquery = (from p in nfmsdb.request_for_refund join lr in nfmsdb.lib_regions on p.region_code equals lr.region_code join lp in nfmsdb.lib_provinces on p.prov_code equals lp.prov_code join lc in nfmsdb.lib_cities on p.city_code equals lc.city_code join lb in nfmsdb.lib_brgy on p.brgy_code equals lb.brgy_code join gts in geotaggingquery on p.sub_project_id equals gts.sub_project_id select new { lb, lc, lp, lr, p, gts }).AsEnumerable();
if (access_user.Select(x => x.RoleId).FirstOrDefault() > 2)
{
nfmsquery = (from p in nfmsdb.request_for_refund join lr in nfmsdb.lib_regions on p.region_code equals lr.region_code join lp in nfmsdb.lib_provinces on p.prov_code equals lp.prov_code join lc in nfmsdb.lib_cities on p.city_code equals lc.city_code join lb in nfmsdb.lib_brgy on p.brgy_code equals lb.brgy_code join gt in nfmsdb.user_municipal_access on p.city_code equals gt.city_code join gts in geotaggingquery on p.sub_project_id equals gts.sub_project_id where gt.user_id == UserId && gt.selected == true select new { lb, lc, lp, lr, p, gts }).AsEnumerable();
}
if (!resint.Contains(pid))
{
nfmsquery = nfmsquery.Where(x => x.gts.project_type_id == pid);
}
if (!resint.Contains(cid))
{
nfmsquery = nfmsquery.Where(x => x.gts.cycle_id == cid);
}
var result = nfmsquery.Select(x => new
{
sub_project_id = x.p.sub_project_id,
sub_project_name = x.p.sub_project_name,
region_name = x.lr.region_name,
region_code = x.lr.region_code,
prov_name = x.lp.prov_name,
prov_code = x.lp.prov_code,
city_name = x.lc.city_name,
city_code = x.lc.city_code,
brgy_code = x.lb.brgy_code,
brgy_name = x.lb.brgy_name,
request_for_refund_id = x.p.request_for_refund_id,
total_sub_project_cost = x.p.total_sub_project_cost,
total_program_cost = x.p.total_program_cost,
region_director = x.p.region_director,
lbp_branch = x.p.lbp_branch,
address = x.p.address,
lcc_amount = x.p.lcc_amount,
account_name = x.p.account_name,
bank_no = x.p.bank_no,
amount_requested = x.p.amount_requested,
tranche_id = x.p.tranche_id,
prev_amount_release = x.p.prev_amount_release,
cumul_total_request = x.p.cumul_total_request,
date_created = x.p.date_created,
date_requested = x.p.date_requested,
brgy_chair_name = x.p.brgy_chair_name,
bspmc_name = x.p.bspmc_name,
ac_name = x.p.ac_name,
lprao_name = x.p.lprao_name,
lprao_date = x.p.lprao_date,
rpc_name = x.p.rpc_name,
rpm_name = x.p.rpm_name,
ac_date = x.p.ac_date,
rpc_date = x.p.rpc_date,
rpm_date = x.p.rpm_date,
updated_by = x.p.updated_by,
date_updated = x.p.date_updated,
isdeleted = x.p.isdeleted,
}).ToList();
return result;
}
I also try var geotaggingquery = (from xx in geotagging.sub_project select xx).ToList() and `var nfmsquery = (from p in nfmsdb.request_for_refund join lr in nfmsdb.lib_regions on p.region_code equals lr.region_code join lp in nfmsdb.lib_provinces on p.prov_code equals lp.prov_code join lc in nfmsdb.lib_cities on p.city_code equals lc.city_code join lb in nfmsdb.lib_brgy on p.brgy_code equals lb.brgy_code join gts in geotaggingquery on p.sub_project_id equals gts.sub_project_id select new { lb, lc, lp, lr, p, gts }).ToList();, nothing happens.
Thanks in advance

Fast join on Multiple IEnumerable

Whith s_records, q_records, d_records, i_records all of type IEnumerable<MyRecord>, querytwo works just as expected. But what if I want to join multiple IEnumerable on the same equality of the same fields?
var querytwo = from a in s_records
join b in q_records
on a.date equals b.date
select new { s_line = a.line, q_line = b.line };
Console.WriteLine(querytwo.Count());
This query doesn't work I am trying to do the same as in querytwo, but join on multiple IEnumerable<MyRecord>:
var query = from a in s_records
join b in q_records
join c in d_records
join d in i_records
on a.date equals b.date equals c.date equals d.date
select new { s_line = a.line, q_line = b.line, d_line = c.line, i_line = d.line };
Your syntax is to off to some extent. it should be:
var querytwo = from a in s_records
join b in q_records on a.date equals b.date
join c in d_records on b.date equals c.date
join d in i_records on c.date equals d.date
select new {
s_line = a.line,
q_line = b.line,
d_line = c.line,
i_line = d.line
};

Linq Joins only working when all tables have data

Below you can find my problem. My view only loops through the data when both of "DocentenCompetenties" and "DocentenLocaties" is filled in. This is a problen because I want to be able to loop them even if one of them doens't have any data
var ShowCompetenties = from d in db.Docent
join dc in db.DocentenCompetenties on d.DocentID equals dc.DocentID
join c in db.Competenties on dc.CompetentiesID equals c.CompetentiesID
join dl in db.DocentenLocaties on d.DocentID equals dl.DocentID
where d.DocentID == id
join l in db.Locaties on dl.LocatieID equals l.LocatieID
select new ShowCompetenties { Docenten = d, Competenties = c, DocentenCompetenties = dc, DocentenLocaties = dl, Locaties = l };
UPDATE
Current Error:
An exception of type 'System.NullReferenceException' occurred in App_Web_xp01otas.dll but was not handled in user code
Additional information: Object reference not set to an instance of an object.
var id = Convert.ToInt32(Session["id"]);
var LeftShowCompetenties = from d in db.Docent
join g1 in db.DocentenCompetenties on d.DocentID equals g1.DocentID into group1
from dc in group1.DefaultIfEmpty()
join c in db.Competenties on dc.CompetentiesID equals c.CompetentiesID
where d.DocentID == id
select new ShowCompetenties { Docenten = d, Competenties = c, DocentenCompetenties = dc};
var RightShowCompetenties = from d in db.Docent
join g3 in db.DocentenLocaties on d.DocentID equals g3.DocentID into group3 from dl in group3.DefaultIfEmpty()
where d.DocentID == id
join l in db.Locaties on dl.LocatieID equals l.LocatieID
select new ShowCompetenties { Docenten = d, Locaties = l, DocentenLocaties = dl };
var ShowCompetenties = LeftShowCompetenties.Union(RightShowCompetenties);
VIEW
<h4>Competenties</h4>
#foreach (var item in Model)
{
if(#item.DocentenCompetenties != null && #item.DocentenCompetenties.DocentID.ToString() != null) {
#item.Competenties.Name #Html.ActionLink("Delete", "DeleteCompetenties", new { id = item.DocentenCompetenties.DocentenCompetentiesID })
}
<h4>Docenten</h4>
#foreach (var item in Model)
{
if(#item.DocentenLocaties != null && #item.DocentenLocaties .DocentID.ToString() != null)
{
#item.Locaties.Name
}
}
You are doing an Inner join this way.
It sounds like you actually want to do an outer join.
Try this:
var ShowCompetenties = from d in db.Docent
join g1 in db.DocentenCompetenties on d.DocentID equals g1.DocentID into group1
from dc in group1.DefaultIfEmpty()
join g2 in db.Competenties on dc.CompetentiesID equals g2.CompetentiesID into group2
from c in group2.DefaultIfEmpty()
join g3 in db.DocentenLocaties on d.DocentID equals g3.DocentID into group3
from dl in group3.DefaultIfEmpty()
where d.DocentID == id
join l in db.Locaties on dl.LocatieID equals l.LocatieID
select new ShowCompetenties { Docenten = d, Competenties = c, DocentenCompetenties = dc, DocentenLocaties = dl, Locaties = l };
This is only a LEFT outer join however, if you wish to do a full outer join. You must first do a left, then a right outer join and finally merge (with Union()) the two.
EDIT
As per the comments, with regards to the error you're getting after the UNION:
var id = Convert.ToInt32(Session["id"]);
var LeftShowCompetenties = from d in db.Docent
join g1 in db.DocentenCompetenties on d.DocentID equals g1.DocentID into group1
from dc in group1.DefaultIfEmpty()
join c in db.Competenties on dc.CompetentiesID equals c.CompetentiesID
where d.DocentID == id
select new ShowCompetenties { Docenten = d, Competenties = c, Locaties = null, DocentenCompetenties = dc, DocentenLocaties = null};
var RightShowCompetenties = from d in db.Docent
join g3 in db.DocentenLocaties on d.DocentID equals g3.DocentID into group3
from dl in group3.DefaultIfEmpty()
where d.DocentID == id
join l in db.Locaties on dl.LocatieID equals l.LocatieID
select new ShowCompetenties { Docenten = d, Competenties = null, Locaties = l, DocentenCompetenties = null, DocentenLocaties = dl };
var ShowCompetenties = LeftShowCompetenties.Union(RightShowCompetenties);
(Check the added Locaties = null and Competenties = null in the constructors.)
VIEW
if (#item.DocentenCompetenties != null){}
if (#item.DocentenLocaties!= null){}
If you have navigation properties set up, it's much easier to left join:
var ShowCompetenties =
from d in db.Docent
where d.DocentID == id
from dc in d.DocentenCompetenties.DefaultIfEmpty()
let c = dc.Competenty
from dl in d.DocentenLocaties.DefaultIfEmpty()
let l = dl.Locaty
select new ShowCompetenties {
Docenten = d,
Competenties = c,
DocentenCompetenties = dc,
DocentenLocaties = dl,
Locaties = l };

Convert special SQL query to Linq

do you know how write this SQL Query to linq ?
SELECT *
FROM
a
INNER JOIN b
ON a.FkSubmissionId = b.Id
RIGHT JOIN c
ON a.FkItemId = c.Id
WHERE
(b.FkUserId = '...' OR b.FkUserId is null)
and
(c.FkTenderId = 2)
I use Linquer and the best I have from the tool is that :
Linq :
from
items in _context.Items
from
si in _context.si
join s in _context.s
on new { fki = si.fki } equals new { fki = s.Id }
into
submissions_join
from
s in submissions_join.DefaultIfEmpty()
...
Result in SQL :
SELECT *
FROM
[Items] AS [t0]
CROSS JOIN [SubmissionsItems] AS [t1]
LEFT OUTER JOIN [Submissions] AS [t2]
ON [t1].[FkSubmissionId] = [t2].[Id]
WHERE
(([t2].[FkUserId] = #p0) OR (([t2].[FkUserId]) IS NULL))
AND
([t0].[FkTenderId] = #p1)
So the final result it not what I get from the query I need...
Thank you for your help !!!
Try this:
var part1 =
from x in a
join y in b on x.FkSubmissionId equals y.Id
where b.FkUserId = "..."
select new {x, y};
var part2 =
from c in z
where c.FkTenderId == 2
join xy in part1
on z.Id equals xy.x.FkItemId
into xys
from xy in xys.DefaultIfEmpty()
select new {xy.x, xy.y, z};
I would reorder your query so you can use a left join instead of a right join
var query = from c in context.C
from a in context.A.Where(x => c.Id == x.FkItemId)
.DefaultIfEmpty()
join b in context.B on a.FkSubmissionId equals b.id
where b.FkUserId == '...' || b.FkUserId == null
where c.FkTenderId == 2
select new {
a,
b,
c
};

Categories