I'm trying to convert "SQL Outer Apply" to Linq.
The SQL is:
select Currencies.Name, Currencies.Sign ,a.ActualPrice
from Currencies
outer apply (select CurrencyID,ActualPrice from Prices
where ProductID=5 and Currencies.ID=Prices.CurrencyID)a
I have tried the following Linq but got one row, instead of row for each currency as the SQL statement gives me.
from c in Currencies
from p in Prices.DefaultIfEmpty()
where p.ProductID.Equals(5) && c.ID==p.CurrencyID
select new {c.Name, p.ActualPrice}
Any solution for this?
Try this:
var result =
Currencies.Select(c => new
{
Name = c.Name,
Sign = c.Sign,
ActualPrice = Prices.Where(p => p.ProductID == 5 &&
p.CurrencyID == c.ID)
.FirstOrDefault()
});
I am not sure if this returns the correct result, because I don't know what happens, when the subselect in outer apply returns multiple rows...
Related
Just assume a simple example:I have two table and use this query:
select *
from People
where PersonGuid = (select PersonGuid from Sellers where Guid = '')
How can I write this query with linq?
I tried this:
var person = from p in loginContext.Person where p.PersonGuid =
(loginContext.Seller.Where(s => s.Guid == sellerGuid).FirstOrDefaultAsync());
but that's wrong.
What is the right way to write it?
If you were to rewrite your SQL query as
select *
from People AS PE
JOIN
Sellers AS Sellers
ON PE.PersonGuid = SE.PersonGuid
WHERE
SE.Guid = ''
then the LINQ becomes a little more obvious:
var person = (from p in loginContext.Person
join s in loginContext.Seller on p.PersonGuid equals s.PersonGuid
where s.guid == ""
select p)
.FirstOrDefault();
Although your SQL would suggest FirstOrDefault is not required.
Warning - not tested.
You could probably try using LINQ JOIN clause.
It should be something like:
from p in loginContext.Person
join s in loginContext.Seller on new { p.PersonGuid = s.Guid }
where s.Guid = sellerGuid
You can know more about LINQ JOIN here -> Microsoft C# Reference
Hope it helps!
I will assume that select PersonGuid from Sellers where Guid = '' will provide a single value no matter what, otherwise your SQL statement would fail.
Accepted answer works, but if you want a solution that keeps the spirit of the SQL query, you can rely on Any function. Something along the following:
var person = await loginContext.Person
.Where(p => loginContext.Sellers
.Any(s => s.PersonGuid == p.PersonGuid && s.Guid = ""))
.FirstOrDefaultAsync();
I expect this to be transformed into an SELECT ... WHERE EXISTS which is similar to your initial query.
Problem Statement:
I'm trying to convert one of my Sql to linq query, but I'm unable to get the desired output which i need. Can anyone suggest me what i should do?
SQL Query:
SELECT AssetTagging.AssetID, AssetTagging.AssetDescription, [Return].RequestStatus
FROM AssetTagging
LEFT OUTER JOIN [Return] ON AssetTagging.AssetID = [Return].AssetID
LEFT OUTER JOIN Issue ON AssetTagging.AssetID = Issue.AssetID
WHERE (Issue.AssetID IS NULL) OR ([Return].RequestStatus = 'Approved')
Linq Query I'm using:
var result = (from at in db.AssetTagging.AsEnumerable()
join r in db.Return on at.AssetID equals r.AssetID
orderby at.AssetID
where !db.Issue.Any(issue=>issue.AssetID==at.AssetID) || r.RequestStatus=="Approved"
select new globalTestModel
{
model1=at
}).ToList();
//I know that in Linq query I'm using Inner join instead of Left Join,but i'm getting error if i use left join instead of inner join?
What am I doing wrong??
Any suggestion to get desired query like Sql in Linq?
Asset Tag table:
Issue table:
Return table:
Desired Output :
You need to remove .AsEnumerable(), because you want your query to be translated to sql. Right now it would be using linq-to-objects and if you are using a left join with linq-to-object you need to check for null reference exceptions. rt could be null, so rt.RequestStatus would throw an exception.
*I believe rt should be r in your example
You can't project to an existing entity, so you need to change your select to:
select new PocoClass
{
model1=at
}
//New class definition
public PocoClass
{
public AssetTagging model1 { get; set; }
}
You need to do like this:
var result = from at in db.AssetTagging
join r in db.Returns on at.AssetID equals r.AssetID into a
from returns into a.DefaultIfEmpty()
join i in db.Issues on at.AssetID equals I.AssetID into b
from issues into b.DefaultIfEmpty()
where issues.AssetID != null || returns.RequestStatus == "Approved"
select new
{
AssetID = at.AssetID,
AssetDescription = at.AssetDescription,
Status = returns != null ? returns.RequestStatus : null
}.ToList();
try like following:
from at in db.AssetTagging
join r in db.Return on at.AssetID equals r.AssetID into res1
from atr in res1.DefaultIfEmpty()
join i in db.Issues on i.AssetID==at.AssetID into res2
from obj in res2.DefaultIfEmpty()
select at
where i.AssetID == null || r.RequestStatus equals "Approved"
Just make two times left outer join and then do filter on where condition.
Also have first look at this msdn article about left outer join using linq.
Try the following I am assuming that you still want the cases where r is null unless r is not null and request status = approved.
You have to check to verify r!=null before checking the request status and you will still need to include when r is null to get the complete result set. I haven't tested this, but this should put you in the right direction.
Good luck.
var result = (from at in db.AssetTagging
join r in db.Return.DefaultIfEmpty()
on at.AssetID equals r.AssetID
join i in db.Issue.DefaultIfEmpty()
on at.AssetID equals i.AssetID
where
(r == null || (r!=null && r.RequestStatus == "Approved"))
|| i == null
select new {
at.AssetID,
at.AssetDescription,
IssueID = (i!=null) ? i.IssueID : null),
ReturnID = (r!=null) ? r.ReturnID: null),
ReturnStatus = (r!=null)
? r.ReturnStatus
: null}).ToList();
I know this isn't exactly what you've asked for, but it might be useful anyway.
If you have access to the database to execute SQL queries, I would suggest creating a view. You can then drop the view into your DBML file the same way as you would with a table, and have much simpler Linq expressions in your C# code.
CREATE VIEW [Asset_Issue_Return_Joined] AS
SELECT AssetTagging.AssetID, AssetTagging.AssetDescription, [Return].RequestStatus
FROM AssetTagging
LEFT OUTER JOIN [Return] ON AssetTagging.AssetID = [Return].AssetID
LEFT OUTER JOIN Issue ON AssetTagging.AssetID = Issue.AssetID
WHERE (Issue.AssetID IS NULL) OR ([Return].RequestStatus = 'Approved')
Here is the complete query
var result = (from assetTagging in db.AssetTagging
join return0 in db.Return on assetTagging.AssetID equals return0.AssetID into returns
from return0 in returns.DefaultIfEmpty()
join issue in db.Issue on assetTagging.AssetID equals issue.AssetID into issues
from issue in issues.DefaultIfEmpty()
where issue.AssetID == null || return0.RequestStatus == "Approved"
select new
{
assetTagging.AssetID,
assetTagging.AssetDescription,
return0.RequestStatus
}).ToList();
I would like to know how can i change the following sql statement into Linq or Lambda Extension in C#
SELECT m.mdes as AgeGroup,COUNT(DISTINCT(mbcd))as "No.of Member" FROM mageg m
LEFT JOIN (select distinct(mbcd) ,mage
FROMtevtl
JOIN mvipm
ON tevtl.mbcd = mvipm.mvip
WHERE datm >= '2014-04-01'
AND datm <= '2014-04-30'
)vip
ON m.tage >= vip.mage AND m.fage <= vip.mage
GROUP BY m.mdes
I manage to do the first half of the LINQ statement. Not sure If it is correct
here is the first half. I do not know how to connect with the left join.
(from mem in mvipms
from log in tevtls
from grp in magegs
where mem.mage >=grp.fage && mem.mage <=grp.tage && mem.mvip.Equals(log.mbcd)
&& log.datm >= DateTime.Parse("2014-04-01") && log.datm <= DateTime.Parse("2014-04-30")
select new {mem.mvip,grp.mdes}).Distinct()
Pls advice. I am using the MSSQL 2008 and VS2010.
Thanks a million.
I am no expert on LINQ, but since no-one else has answered, here goes!
Firstly you cannot (AFAIK) do a LINQ join on anything other than equals so the structure of your LEFT JOIN has to change. Partly for debugging purposes, but also for readability, I prefer to layout my LINQ in bite-size chunks, so what I would do in your case is something like this (assuming I have understood your data structure correctly):
var vip = (from t in tevtl
join v in mvipl
on t.mbcd equals v.mvip
where t.datm >= new DateTime(2014, 4, 1) && t.datm <= new DateTime(2014, 4, 30)
select new { t.mbcd, v.mage }).Distinct();
var mv = from m in magegl
from v in vip
where m.tage >= v.mage && m.fage <= v.mage
select new
{
m.mdes,
v.mbcd
};
var gmv = from m in mv
group m by new { m.mdes } into grp
select new
{
mdes = grp.Key.mdes,
CountMBCD = grp.Count()
};
var lj = from m in magegl
join v in gmv
on m.mdes equals v.mdes into lhs
from x in lhs.DefaultIfEmpty()
select new
{
AgeGroup = m.mdes,
CountMBCD = x != null ? x.CountMBCD : 0
};
By way of explanation. mv is the equivalent structure for your left join in that it has the relevant where clause, but obviously it does not contain any nulls - it is equivalent to an INNER JOIN. gmv is a group on mv, so is still effectively an INNER JOIN. Then to pick up the missing mdes (if any) I re-join on magel with the added syntax DefaultIfEmpty() - this converts the join into the equivalent of a LEFT OUTER JOIN.
Without any sample data, I haven't been able to test this, but I hope it gives you enough to point you in the right direction!
When this gets called two times, the second invocation doesn't re-run the query on the database, the query caching works.
var query = from p in session.Query<Product>()
where p.YearIntroduced >= 0
select p;
query = query.Cacheable();
var t = query.ToList();
However, when I put some join on the query, the query cache is not working anymore, hence when this is invoked two times, the query is invoked on database two times too:
var query = from p in session.Query<Product>()
join l in session.Query<ProductLanguage>()
on p.ProductId equals l.ProductId
where p.YearIntroduced >= 0
select new { p, l };
query = query.Cacheable();
var t = query.ToList();
Might be a dumb question, is query caching can work on one table only, hence when adding a join, the query is not cacheable anymore?
What's the solution to make a query cacheable even it has a join?
Another oddity, the query caching with join will work if I remove the where clause. When this gets called two times, the second invocation doesn't re-run the query on database, the query caching works
var query = from p in session.Query<Product>()
join l in session.Query<ProductLanguage>()
on p.ProductId equals l.ProductId
select new { p, l };
query = query.Cacheable();
var t = query.ToList();
But what's the use of a query when you can't put a where clause on it?
Is this an NHibernate bug, or am I just using query caching the wrong way?
Found the solution, put the Where clause on the final part of the query:
var query = from p in session.Query<Product>()
join l in session.Query<ProductLanguage>()
on p.ProductId equals l.ProductId
select new { p, l };
query = query.Where(x => x.p.ProductId && x.l.LanguageCode == "en").Cacheable();
var t = query.ToList();
I have write the below query in simple SQL,
I want to change it to use LINQ, I have tried, but my LINQ query and the original SQL statement are giving different record sets.
Simple SQL Query:
select *
from Paymentadvices
where status = 3
and Id in (select PaymentAdviceId from Approvals where ApprovedById = 13)
LINQ:
var myPaymentAdviceList = from pa in db.PaymentAdvices
where pa.Status == 3
join Ap in db.Approvals on pa.Id equals
Ap.PaymentAdviceId
where Ap.EmployeeId == 13
orderby pa.PaidDate descending
select pa;
I am not supposed to use join I guess, What should I use ?
var a = db.Approvals.Where( x => x.ApprovalById = 13).PaymentAdviceId;
var b = db.Paymentadvices.Where(x => x.status ==3 && a.Contains(x.Id);
.Contains() makes the WHERE IN () , you don't need a join there
var a = from a in db.Approvals
where a.ApprovedById == 3
select a.PaymentAdviceId;
var b = (from p in db.PaymentAdvices
where p.Status == 3 &&
a.Contains(p.Id)
select p).ToList();
those are both linq , the top is just lambda expressions which are commonly used in Linq queries. I would reccommend that you get used to reading/ writing both styles . The majority of code you'll come across in lambda style
I believe something like the below would work:
var query = from p in db.PaymentAdvices
where p.Status == 3 && db.Approvals
.Select(a => a.Id)
.Where(a => a.ApprovedById == 13)
.Contains(p.Id)
select p;
Though it's worth noting that #Scott Selby and #axrwkr solutions above are essentially the exact same thing in another form.