LINQ with multiple left join and where clause - c#

I have following query, and I am converting it to LINQ.
select acq.ACQPub as Prev_ACQPub
, ve.CompanyID
, ve.EntityID
, ve.RoundID
, ve.EntityName
, ve.Date
, ve.RoundTypeCode
, ve.EventType
, ve.PostValue_DJVS
, ve.PostVal
, ve.PreVal
, fin.FinanceStat
from ValuationEvents_PIT_New as ve
left join Acq_PublicDummy as acq
on ve.EntityID = acq.EntityID
left join FinStat_New as fin
on ve.EntityID = fin.EntityID
where ve.EventType in('ACQ','LBO')
and acq.ACQPub is null
I wanted to double check if I've done it right or there is a better way of doing it.
Here is my code:
return (from ve in valuationEvents where ve.EventType == EventTypes.Acq || ve.EventType == EventTypes.Lbo
join acq in acqPublicDummies on ve.EntityId equals acq.EntityID into veAcq
from x in veAcq.DefaultIfEmpty() where x != null && x.ACQPub == null
join fin in finStats on ve.EntityId equals fin.EntityID into veFin
from y in veFin.DefaultIfEmpty()
select new AcqResearch
{ PrevAcqPub = x == null ? null : x.ACQPub,
EntityId = ve.EntityId,
CompanyId = ve.CompanyId,
RoundId = ve.RoundId,
Date = ve.Date,
RoundTypeCode = ve.RoundTypeCode,
EventType = ve.EventType.ToString(),
PostValueDjvs = ve.PostMoneyValue,
PostVal = ve.PostVal,
PreVal = ve.PreVal,
FinanceStat = y == null ? null : y.FinanceStat
}).ToList();
Since result will be used > 1 times I am returning List instead of IEnumerable.
Also I can't run SQL and compare result of it with LINQ result, since query above runs against of Raw data and LINQ is running after data calculations and additional cleansing process. So there is no way for me to compare query result with my LINQ result. I just need to rely that logic is correct. What is the same is SQL logic and LINQ logic.
Thank you very much for your help and feedback!

If you want to verify that the query is the same, you can look at the SQL that is generated from the linq. there are a few ways of doing this:
Use SQL Profiler
Paste the query into LinqPad and view the SQL tab
Set the Log property on your datacontext
You can then compare the two SQL queries and check for differences.
As an aside, in your case the only things I would change are style related - I would move all of the where clauses to just above the select clause, so it is easier to see what filter you are applying. Also, the line
PrevAcqPub = x == null ? null : x.ACQPub
Seems like it may as well be
PrevAcqPub = null
Since you have already filtered out all x that are null and that have x.ACQPub != null (Same goes for the SQL query).

Your solution looks correct to me

Related

SQL inner select to LINQ

This thing is driving me crazy.
I think its not that complicated but I don't get it.
I have this working SQL statement and I need the Linq statement for it.
select
a.id, a.date,
(select top 1 b.price from b where a.id = b.id and a.date >= b.date) as price
from a;
For explanation:
I have a table a with articles and a table b with a price history.
Now I need a datagrid where I can enter new entries for table a (so a view is not working) and after saving its showing me associated price
I hope I could express myself understandably
For translating SQL to LINQ query comprehension:
Translate FROM subselects as separately declared variables.
Translate each clause in LINQ clause order, leaving monadic operators (DISTINCT, TOP, etc) as functions applied to the whole LINQ query.
Use table aliases as range variables. Use column aliases as anonymous type field names.
Use anonymous types (new { }) for multiple columns
Left Join is simulated by using a into join_variable and doing another from from the join variable followed by .DefaultIfEmpty().
Replace COALESCE with the conditional operator and a null test.
SELECT * must be replaced with select range_variable or for joins, an anonymous object containing all the range variables.
SELECT fields must be replaced with select new { ... } creating an anonymous object with all the desired fields or expressions.
Proper FULL OUTER JOIN must be handled with an extension method.
For your query:
var ans = from ra in a
select new {
ra.id,
ra.date,
price = (from rb in b
where ra.id == rb.id && ra.date >= rb.date
select rb.price).First()
};
I'm not sure which syntax you're aiming for, but one of these should do the trick. I haven't tested it though.
from xa in a
select new
{
id,
date,
price = (
from xb in b
where xa.id == xb.id && xa.date >= xb.date
select xb.price
).First() // or .FirstOrDefault() if you want to allow null prices
};
or
a.Select(xa => new
{
id,
date,
price = b.First(xb => xa.id == xb.id && xa.date >= xb.date) // or .FirstOrDefault() if you want to allow null prices
});

Using SQL instead of LINQ in Telerik Open Access

I'm using Telerik Open Access. I have two separate projects that have Open Access data and then a third project that has the bulk of my code. I've been working on a way to convert a simple (at least I thought it was) SQL query to LINQ so that I can get the data I need. I have not been successful. I've had to break a single LINQ query into separate queries, because of the need for the Trim() function (I think). This has led to a lengthy piece of code and I'm still not getting the same results as my SQL query.
So my question is, is there anyway to use SQL instead of LINQ to access the data in the Open Access projects? If so, can you show me the syntax to do that for my query?
If it is not possible to use SQL, can you show me show me the proper way to convert my SQL query into LINQ so that I get the same results?
Thank you.
My SQL query is
SELECT DISTINCT us2.ccustno, us2.dispname, us2.csiteno, so.s1_name
FROM [DALubeDeacom].[dbo].[dmbill] bi
INNER JOIN [DALubeDeacom].[dbo].[dmso1] so
ON bi.bi_s1id = so.s1_id
INNER JOIN [DALubeNew].[dbo].[usersecurity] us2
ON so.s1_name = us2.cparentno
WHERE
us2.ctype = 'JOBSITE'
AND us2.csiteno is not null
AND us2.csiteno != ''
AND bi.bi_smid = '22'
ORDER BY us2.csiteno
My LINQ query is
public List<DataModelSample> GetLocationsBySalesNo(string salesNo)
{
int iSalesNo = int.Parse(salesNo.Trim());
try
{
var dmso = (
from so in deacom.Dmso1
join qt in deacom.Dmbills
on so.S1_id equals qt.Bi_s1id
where qt.Bi_smid == iSalesNo
select new Dmso1
{
S1_id = so.S1_id
, S1_name = so.S1_name.Trim()
}
);
var usec = (
from us in dbContext.Usersecurities
where us.Cparentno != null && us.Cparentno.Trim() != "" && us.Ctype.Trim() == "JOBSITE" && us.Csiteno.Trim() != ""
select new Usersecurity
{
Ccustno = us.Ccustno.Trim(),
Csiteno = us.Csiteno.Trim(),
Dispname = us.Dispname.Trim(),
Cparentno = us.Cparentno.Trim()
}
);
var customers =
(
from us in usec
join so in dmso
on us.Cparentno equals so.S1_name
select us
);
customers = customers.GroupBy(x => x.Csiteno).Select(x => x.First());
List<DataModelSample> listLocations =
(
from c in customers
select new DataModelSample
{
customerID = c.Ccustno
,
origLocationName = c.Csiteno + " " + c.Dispname
,
origLocationID = c.Csiteno
}
).OrderBy(x => x.origLocationID).ToList();
return listLocations.ToList();
}
catch (Exception ex)
{
throw ex;
}
} // GetLocationsBySalesNo(userInfo.csalesno)
Edit 1 - 2-19-16
Tried a suggestion by ViktorZ. His query was similar to the one I first tried. It returned the error "Identifier 'Ctype' is not a parameter or variable or field of 'DALube_DeacomModel.Dmbill'. If 'Ctype' is a property please add the FieldAlias or Storage attribute to it or declare it as a field's alias." From an online search, it looked like this was do to "extended fields". I don't seemed to be using such fields. The only way I could get around this error was to break it into the smaller LINQ queries in my original question, which didn't produce the right results. Any suggestions?
Here's the code:
var query = (from bill in deacom.Dmbills
join so in deacom.Dmso1 on bill.Bi_s1id equals so.S1_id
join us in dbContext.Usersecurities on so.S1_name equals us.Cparentno
where us.Ctype == "JOBSITE"
&& us.Csiteno != null
&& us.Csiteno != string.Empty
&& bill.Bi_smid == iSalesNo
select new
{
ccustno = us.Ccustno.Trim(),
dispname = us.Dispname.Trim(),
csiteno = us.Csiteno.Trim(),
s1_name = so.S1_name.Trim()
}).Distinct();
One very crude approximation of your SQL query is:
var query = (from bill in deacom.Bills
join so in deacom.LubeDeacom on bill.bi_s1id equals so.s1_id
join us in deacom.UserSecurity on so.s1_name equals us.cparentno
where us.ctype = "JOBSITE"
&& us.csiteno != null
&& us.csiteno != string.Empty
&& bill.smid = '22'
order by us.csiteno
select new
{
us.ccustno.Trim(),
us.dispname.Trim(),
us.csiteno.Trim(),
so.s1_name.Trim()
}).Distinct();
// to check the translation result
string sql = query.ToString()
// to get the results
var result = query.ToList()
If this is not working for you, you can always fall back to Telerik Data Access ADO.NET API. Here is a documentation article how to use it.

Conversion of SQL into LINQ

I need help converting some an SQL select into LINQ
Here is the original SQL:
Select Top 1 IsNull(ct.Template, t.Template) as Template
From Template t
Left Outer Join ClientTemplate ct On t.TemplateTypeId = ct.TemplateTypeId And ct.ClientId = 149
Where t.TemplateTypeId = (Select TemplateTypeId From QuoteType Where QuoteTypeId = 7)
Order By t.Version DESC, ct.Version DESC
I'm using Entity Framework and have entities for QuoteTypes, ClientTemplates and Templates.
The above SQL gets the Template from the ClientTemplate table for client 149 (uses a variable in the real code) for a particular QuoteType. If there is no entry in the CLientTemplate table then it returns the Template from the main Template table for the same QuoteType!
My idea was to query the QuoteType first and then query the ClientTemplate table to see if one exists and if not query the Template table instead. The problem is this will result in three queries but I'm sure it can be done in one swoop!?
Can anyone have a go at writing the LINQ for me?
Here's my mess so far:
QuoteType quoteType = (from qt in this.entities.QuoteTypes where qt.QuoteTypeID == this.SelectedNewQuoteTypeID select qt).First();
if (quoteType != null && quoteType.TemplateTypeID.HasValue)
{
int quoteTypeTemplateTypeID = (int)quoteType.TemplateTypeID;
var query = (from t in this.entities.Templates
join ct in this.entities.ClientTemplates on t.TemplateTypeID equals ct.TemplateTypeID
into a
from b in a.DefaultIfEmpty(new ClientTemplate())
where t.TemplateTypeID == quoteTypeTemplateTypeID
orderby t.Version descending
select new
{
T1 = t.Template1,
T2 = b.Template
}).First();
// Check the query to see if T1 and T2 are null and use whichever one isn't!
// TODO !!!
}
else
{
return string.Empty;
}
I kind of gave up once I got that far and posted this! My example still does two queries and does not select based on the client ID. It also does not have the second order by on the client template table.
I've inherited the original SQL statement so maybe the problem is with that being badly written in the first place!?
Over to you...
I haven't tested it but maybe you could try something like this
from t in this.entities.Template
from ct in this.entities.ClientTemplate.Where(x => t.TemplateTypeId == ct.TemplateTypeId && ct.ClientId == 149).DefaultIfEmpty()
where t.TemplateTypeId == (from x in this.entities.QuoteType where x.QuoteTypeId == 7 select x.TemplateTypeId).FirstOrDefault()
orderby t.Version descending, ct.Version descending
select new { ct.Template == null ? t.Template : ct.Template }
I think this might work, although this is untested, from reading it appears you can't add multiple join conditions to a LinQ statement so you can just specify it in the where clause
So here ya go, I tried to convert the SQL word for word so here's my attempt. If it does everything I think it will do it will work.
int templateTypeId;
templateTypeId= (context.QuoteType.Where(x => x.QuoteTypeId == 7)).FirstOrDefault().TemplateTypeId
var qry =(
from t in context.Template
join ct in context.ClientTemplate on
t.TemplateTypeId equals ct.TemplateTypeId into cts
from ct in cts.DefaultIfEmpty() //left join
where t.TemplateTypeId == templateTypeId
&& ct.ClientId == 149
order by t.Version descending, ct.Version descending
select new
{
Template = (ct.Template != null) ? ct.Template : t.Template //ternary operator
}).FirstOrDefault();

T-SQL to LINQ conversion

I have the following SQL statement
SELECT
c.CorpSystemID, c.SystemName ,
case when a.TaskItemID is NULL then 'false' else 'true' end as Assigned
FROM CorpSystems c
LEFT OUTER JOIN
(SELECT CorpSystemID, TASKItemID
FROM AffectedSystems
where TASKItemID = 1) a ON c.CorpSystemID = a.CorpSystemID
Can anyone please help me to convert this statement to LINQ?
Thank you.
Ok so assume you've got a list of your CorpSystem objects in a variable called Corpsystems and a list of your AffectedSystem objects in a variable called AffectedSystems. Try the following:
Edit: For a join on all Affected Systems, try this:
var matches = from c in CorpSystems
join a in AffectedSystems on c.CorpSystemId equals a.CorpSystemId into ac
from subSystem in ac.DefaultIfEmpty()
select new
{
c.CorpSystemId,
c.SystemName,
Assigned = subSystem != null && subSystem.TaskItemId != null
};
Or for just AffectedSystems that have a TaskItemId of 1:
var matches = from c in CorpSystems
join a in AffectedSystems.Where(as => as.TaskItemId == 1)
on c.CorpSystemId equals a.CorpSystemId into ac
from subSystem in ac.DefaultIfEmpty()
select new
{
c.CorpSystemId,
c.SystemName,
Assigned = subSystem != null && subSystem.TaskItemId != null
};
See the answers to the following SO question SQL to LINQ Tool, assuming that you do not want to go through the process by hand.

How to check the null of an embedded linq to entities statement

Using linq to entities i am connecting to a database, the database has tables in it that has payments that have a multi to multi relationship with jobs. This is acheived via an allocs table. I want a list box with all the jobs that has a column called due price which takes all of the allocations of payments for this job and takes that away from the job price. However, using the below linq to entities statement. The problem is that if the job has no allocations it returns null and therefore the due payment is empty. What i really want is for the due payment to be the job price if there are no allocations however, i cannot think of a way around this. Please help before i finally go insane :-(
var jobs = from j in data.jobs
where j.property.customer.id == customerid
&& j.completed != null
select new
{
j.id,
j.price,
dueprice = j.price - ( from a in data.allocs
where a.job.id == j.id
select a.amount ).Sum(),
lineone = j.property.lineone,
postcode = j.property.postcode,
jobtype = j.jobtype.name,
j.completed
};
You can also use the Null Coalescing operator to simplify code like this:
dueprice = j.price - (( from a in data.allocs
where a.job.id == j.id
select a.amount ).Sum() ?? 0)
This operator returns the first value which is not null, so myNum ?? 0 will return myNum if it is not null, and if it is null the operator will return 0.
select a.amount ).Concat(/* array with one zero element */).Sum()
I actually found an answer my self, i will try oleg's as well as it seems to be a little more precise but i thought of doing this
dueprice = j.price - (( from a in data.allocs
where a.job.id == j.id
select a.amount ).Sum())==null ? j.price:
//sets the due price to the normal sum if it has allocs
j.price - ( from a in data.allocs
where a.job.id == j.id
select a.amount ).Sum(),
however i like the idea of only adding on more line of code instead of my several(plus it's repeated code) i will try this and let you all know. Thanks for the response.

Categories