I have a outer join with a where clause. It returns multiple responses and I need to select the first one.
from p in context.Persons
join c in context.Companies on p.PersonId equals c.CompanyId
join a1 in context.Addresses on p.AddressDeliveryId equals a1.AddressId into da from x1 in da.DefaultIfEmpty()
join a2 in context.Addresses on p.AddressInvoiceId equals a2.AddressId into ia from x2 in ia.DefaultIfEmpty()
//This line returns multiple answers
join a3 in context.Addresses on p.PersonId equals a3.PersonId into pa from x3 in pa.Where(a3 => a3.AddressLocationId == 5).DefaultIfEmpty()
orderby p.PersonId descending
where p.IsProvider.Equals(false)
&& p.Obsolete.Equals(false)
&& p.Locked.Equals(false)
&& p.IsCustomer.Equals(true)
&& p.PersonType.Equals(1)
select new
{
p, c, x1, x2, x3
};
So I need the x3 to only return the first row. Please help
This worked for me.
from p in context.Persons
join c in context.Companies on p.PersonId equals c.CompanyId
join a1 in context.Addresses on p.AddressDeliveryId equals a1.AddressId into da
from x1 in da.DefaultIfEmpty()
join a2 in context.Addresses on p.AddressInvoiceId equals a2.AddressId into ia
from x2 in ia.DefaultIfEmpty()
let a3 = context.Addresses.FirstOrDefault(a3 => a3.AddressLocationId == 5 && a3.PersonId == p.PersonId && a3.Obsolete == false)
//This line worked for me
orderby p.PersonId descending
where p.IsProvider.Equals(false)
&& p.Obsolete.Equals(false)
&& p.Locked.Equals(false)
&& p.IsCustomer.Equals(true)
&& p.PersonType.Equals(1)
select new
{
p,
c,
DeliveryAddress = x1.Address1,
DeliveryAddressCity = x1.PoCity,
DeliveryAddressZipCode = x1.PoPostalCode,
InvoiceAddress = x2.Address1,
InvoiceAddressCity = x2.PoCity,
InvoiceAddressZipCode = x2.PoPostalCode,
PhoneNumber = a3.Address1,
PhoneNumberAddressId = (a3 != null) ? a3.AddressId : -1,
};
I think you can just change the .DefaultIfEmpty() to .FirstOrDefault()
join a3 in context.Addresses on p.PersonId equals a3.PersonId into pa from x3 in pa.Where(a3 => a3.AddressLocationId == 5).FirstOrDefault()
This should only return you the first x3 element
Related
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
}
I have a SQL query:
SELECT distinct A.stock_value_site,
A.BALANCE_QUANTITY,
A.BALANCE_NOMINAL_VALUE,
A.BALANCE_INDEXED_VALUE,
V.STOCK_VALUE_ORDER,
U.BALANCE_QUANTITY
FROM svr A,
svt V,
svu U
WHERE V.Code = 500 and
A.Id = U.ID (+) and
A.Id = (SELECT max(B.id)
FROM svr B,
sts
WHERE A.stock_value_site = B.stock_value_site and
B.Id = sts.ID(+) and
B.item = _item and
B.date < _from_date and
B.Id IS NULL)
I tried to convert this query to Linq to entities:
var data = (from A in _context.svr
join V in _context.svt on A.svtId equals V.Code
join U in _context.svu on A.Id equals U.Id into groupA
from gA in groupA.DefaultIfEmpty()
where V.Code == _openBalanceRecordId &&
A.Id == (from B in _context.svr
join st in _context.sts on B.Id equals st.Id into groupB
from gB in groupB.DefaultIfEmpty()
where A.svsId == B.svsId &&
B.ItemId == _item &&
B.Date < _startDate.Date
select B.Id).Max()
select new
{
A.stock_value_site,
A.BALANCE_QUANTITY,
A.BALANCE_NOMINAL_VALUE,
A.BALANCE_INDEXED_VALUE,
V.STOCK_VALUE_ORDER,
gA == null ? 0 : gA.BALANCE_QUANTITY
}).Distinct().ToList();
When I run the SQL query in oracle I get 33 records back. But when I run it using Linq to entities I don't get any record.
What am I doing wrong?
I believe there are still some issues with you're original query, if I understand what you're trying to do, this should work better:
var results =
(from a in _context.svr
from v in _context.svt.Where(t => t.Code == 500)
join u in _context.svu on u.Id equals a.Id into gU
from x in gU.DefaultIfEmpty()
where a.Id ==
(from b in _context.svr
join s in _context.sts on b.Id equals s.Id
where b.item = _item
and b.date < _from_date
and b.svsId == a.svsId
select b.Id).Max()
select new
{
a.stock_value_site,
a.BALANCE_QUANTITY,
a.BALANCE_NOMINAL_VALUE,
a.BALANCE_INDEXED_VALUE,
v.STOCK_VALUE_ORDER,
x == null ? 0 : x.BALANCE_QUANTITY
}).Distinct().ToList();
Or possibly this:
var results =
(from a in _context.svr
from v in _context.svt.Where(t => t.Code == 500)
join u in _context.svu on u.Id equals a.Id into gU
from x in gU.DefaultIfEmpty()
let subQuery =
(from b in _context.svr
join s in _context.sts on b.Id equals s.Id
where b.item = _item
and b.date < _from_date
select new { b.Id, b.svsId })
join y in subQuery on a.svsId equals y.svsId into gY
where a.Id = y.Max(b => b.Id)
select new
{
a.stock_value_site,
a.BALANCE_QUANTITY,
a.BALANCE_NOMINAL_VALUE,
a.BALANCE_INDEXED_VALUE,
v.STOCK_VALUE_ORDER,
x == null ? 0 : x.BALANCE_QUANTITY
}).Distinct().ToList();
I would like to know how to do a linq join with multiple conditions and ORs.
Example:
var i = (from d in context.Table1
join b in context.Table2
on new {r1 = d.col1, r2 = d.col2}
equals new {r1 = b.col1, r2 = b.col2}
|| b.col3.ToLower() equals "xyz"
into bd
from k in bd.DefaultIfEmpty()
The ORs part is blowing up.
SQL example:
SELECT * FROM Table1 T1
LEFT JOIN Table2 T2 ON (T1.Col1 = T2.Col1 AND T1.Col2 =T2.Col2)
OR (T1.Col1 = T2.Col1 AND T2.Col2 = 'XYZ')
Explanation:
T1.Col1 must match T2.COl1 - REQUIRED JOIN
Then
T1.Col2 has to match T2.Col2 unless T2.COl2 = "XYZ" then join only on Col1
Try moving the "join" into the "Where" clause ala ANSI 82:
var i = (from d in context.Table1
from b in context.Table2
where (b == null)
|| (d.col1 = b.col1 && d.col2 == b.col2 )
|| (b.col3.ToLower() == "xyz")
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
};
var query_loc = (from at in db.amenities_types
join a in db.amenities on at.id equals a.amenities_type
join u in db.unitInfos on a.unit_id equals u.id
join l in db.locations on u.locations_id equals l.id
join o in db.organizations on l.organization_id equals o.id
join ot in db.organization_types on o.id equals ot.organization_id
where (((u.price >= low_rent) && (u.price <= high_rent))
|| (u.price == null))
&& (u.bedrooms <= beds) && (u.bathrooms <= baths)
&& amenities_list.Contains(at.id)
&& (((ot.active == true) && (DateTime.Now <= ot.deactivateDate))
|| ((ot.active == true) && (ot.deactivateDate == null)))
&& (((l.active == true) && (DateTime.Now <= l.deactivateDate))
|| ((l.active == true) && (l.deactivateDate == null)) )
&& (ot.type == 8)
orderby o.name ascending, l.name ascending
select new { l, o, u, ot, at });
The specific line I need to replace is
where
amenities_list.Contains(at.id)
Instead it needs to produce SQL like this ([at.id] = 29 AND [at.id] = 30 AND [at.id] = 40)
So how do I get my List to produce the above SQL code in LINQ to SQL.
Please create methods for your clauses, you are scaring me.
var query_loc = (from at in db.amenities_types
join a in db.amenities on at.id equals a.amenities_type
join u in db.unitInfos on a.unit_id equals u.id
join l in db.locations on u.locations_id equals l.id
join o in db.organizations on l.organization_id equals o.id
join ot in db.organization_types on o.id equals ot.organization_id
where
PriceIsValid(u)
&& BedsAndBathsArevalid(u)
&& AtIdIsValid(at.id)
&& SomeCrazyDateConditionIsValid(ot, l)
&& TheOtTypeIsValid(ot)
orderby o.name ascending, l.name ascending
select new { l, o, u, ot, at });
And if you mean at.is = 29 OR at.id = 30 OR at.id = 40, then use an AtIdIsValid(at.id) predicate like:
bool AtIdIsValid(int atId){ return (atId == 29 || atId == 30 || atId == 40); }