left join linq query in FF4 - c#

I have the following SQL Query:
SELECT DISTINCT *
FROM Documents d
LEFT JOIN
Invoices
ON (i.invoicedocumentid = d.id or i.jobsheetdocumentid = d.id)
INNER JOIN
PurchaseOrders PO ON i.poid = PO.id
LEFT JOIN
HelpDeskFaults f
ON f.id = PO.helpDeskFaultId
LEFT JOIN stores s
ON s.id = f.storeid
WHERE s.name = 'Linden Drive'
OR d.id in (
SELECT u.id as 'docid'
FROM documents u
INNER JOIN stores s
ON u.storeid = s.id
WHERE s.name = 'Linden Drive'
)
ORDER BY d.Id
So far my linq query looks like this:
var documents = from doc in context.Documents
from invoice in context.Invoices
join po in context.PurchaseOrders on invoice.PurchaseOrder.PurchaseOrderId equals po.PurchaseOrderId
join hdf in context.HelpDeskFaults on po.HelpdeskFaultId equals hdf.ID into hdfpo
from hs in hdfpo.DefaultIfEmpty()
join store in context.Stores on hs.StoreID equals store.ID into hsstore
from hss in hsstore.DefaultIfEmpty()
where hss.Name.Contains(jobSearchParams.StoreName) && (invoice.InvoiceDocumentId == doc.ID || invoice.JobSheetInvoiceId == doc.ID)
select doc;
But the sql that is produced is nothing like what I expected.
Can anyone give me any pointers of how to improve my linq query.

This is what I would translate your SQL query into
var results =
(from doc in context.Documents
from invoice in (
from inv in context.Invoices
where inv.InvoiceDocumentId == doc.ID || inv.JobSheetInvoiceId == doc.ID
select inv).DefaultIfEmpty()
from hs in invoice.PurchaseOrder.HelpDeskFaults.DefaultIfEmpty()
from hss in hs.Stores.DefaultIfEmpty()
where hss.Name == "Linden Drive" || doc.Store.Name == "Linden Drive"
order by doc.ID
select new
{
Document = doc,
Invoice = invoice,
invoice.PurchaseOrder,
HelpDeskFault = hs,
Store = hss,
}).Distinct();
I included that anonymous class of the 5 entities because your SQL is using Select *. I would recommend changing it to only return the minimum required set of fields.

Related

Select IN LINQ to entities with inner joins

I have the follow SQL query
SELECT ob.PK_OBJETIVO,
ev.NM_EVENTO,
ifi.QT_NOTA_IMPACTO,
imi.QT_NOTA_IMPACTO,
ire.QT_NOTA_IMPACTO,
(ifi.QT_NOTA_IMPACTO + imi.QT_NOTA_IMPACTO + ire.QT_NOTA_IMPACTO)/3 AS
Media
FROM AVALIACAO_IMPACTO AS ai
INNER JOIN EVENTO AS EV ON ev.PK_EVENTO = ai.FK_AVALIACAO_IMPACTO_EVENTO
INNER JOIN OBJETIVO AS ob ON ob.PK_OBJETIVO =
ai.FK_AVALIACAO_IMPACTO_OBJETIVO
INNER JOIN IMPACTO_FINANCEIRO AS ifi ON ifi.PK_IMPACTO_FINANCEIRO =
ai.FK_AVALIACAO_IMPACTO_IMPACTO1
INNER JOIN IMPACTO_MISSAO AS imi ON IMI.PK_IMPACTO_MISSAO =
AI.FK_AVALIACAO_IMPACTO_IMPACTO2
INNER JOIN IMPACTO_REPUTACAO AS IRE ON IRE.PK_IMPACTO_REPUTACAO =
AI.FK_AVALIACAO_IMPACTO_IMPACTO3
WHERE ai.FK_AVALIACAO_IMPACTO_OBJETIVO IN
(SELECT OBJ.PK_OBJETIVO
FROM OBJETIVO AS OBJ
WHERE OBJ.FK_OBJETIVO_PROCESSO = 3)
I need to transform that query in a LINQ query, I tried that:
var queryImpactos = await _context.AvaliacaoImpacto
.Where(e => _context.Objetivo.Select(o =>
o.ProcessoID).Contains(planoRiscos.Auditoria.ProcessoID))
.Include(e => e.Evento).Include(e => e.Objetivo)
.Include(e => e.ImpactoFinanceiro).Include(e =>
e.ImpactoMissao).Include(e => e.ImpactoReputacao).ToListAsync();
"planoRiscos.Auditoria.ProcessoID" returns what it takes, the number 3 of the pure SQL query, but the query result is returning all the records in the AVALIACAO_IMPACTO table, however I only need the records where a FK_OBJETIVO in AVALIACAO_IMPACTO exists within the OBJETIVO table, where the FK_PROCESSO in OBJETIVO is equal to the passed parameter (planoRiscos.Auditoria.ProcessoID).
Tip: whenever you need to convert SQL query to a LINQ query, make the query syntax your first choice.
Try this:
var queryImpactos = from ai in AVALIACAO_IMPACTO
join
ev in EVENTO on ai.FK_AVALIACAO_IMPACTO_EVENTO equals ev.PK_EVENTO
join ob in OBJETIVO on ai.FK_AVALIACAO_IMPACTO_OBJETIVO equals ob.PK_OBJETIVO
join ifi in IMPACTO_FINANCEIRO on ai.FK_AVALIACAO_IMPACTO_IMPACTO1 equals ifi.PK_IMPACTO_FINANCEIRO
join imi in IMPACTO_MISSAO on ai.FK_AVALIACAO_IMPACTO_IMPACTO2 equals imi.PK_IMPACTO_MISSAO
join IRE in IMPACTO_REPUTACAO on ai.FK_AVALIACAO_IMPACTO_IMPACTO3 equals IRE.PK_IMPACTO_REPUTACAO
where (from obj in OBJETIVO where obj.FK_OBJETIVO_PROCESSO == 3 select obj.PK_OBJETIVO).Contains(ai.FK_AVALIACAO_IMPACTO_OBJETIVO)
select new
{
ob.PK_OBJETIVO,
ev.NM_EVENTO,
QT_NOTA_IMPACTO1 = ifi.QT_NOTA_IMPACTO,
QT_NOTA_IMPACTO2 = imi.QT_NOTA_IMPACTO,
QT_NOTA_IMPACTO3 = IRE.QT_NOTA_IMPACTO,
Media = (ifi.QT_NOTA_IMPACTO + imi.QT_NOTA_IMPACTO + IRE.QT_NOTA_IMPACTO) / 3
};
Hope it's what you're looking for!

Linq 'Unable to process the type 'Anonymous type', because it has no known mapping to the value layer.' in MVC

I am trying to convert a SQL Command to Linq but gets the error 'Unable to process the type 'Anonymous type', because it has no known mapping to the value layer.'
SQL Code
SELECT ooe.id, parts.title, appro.totalAppro, allo.TotalAllotment, cost.total_cost, (CASE WHEN cost.total_cost IS NULL THEN (SELECT allo.TotalAllotment) ELSE (SELECT allo.TotalAllotment - cost.total_cost) END) AS unobligated
FROM pmTA_OoeGeneral AS ooe INNER JOIN
pmTA_Particulars AS parts ON ooe.particular_id = parts.id LEFT OUTER JOIN
pmTA_vwObligationRequestDetailsTotalCostByOoe AS cost ON ooe.id = cost.ooe_general_id
LEFT OUTER JOIN pmTA_vwTotalAllotmentGeneralFund AS allo ON ooe.id = allo.ooe_general_id
LEFT OUTER JOIN pmTA_vwTotalAppropriationGeneralFund AS appro ON ooe.id = appro.ooe_general_id
WHERE (ooe.year = #year) AND (ooe.project_category_id = #cat) and (ooe.type = #type) order by ooe.id
LINQ Code
var gvStatusGenOffices = (from a in db.iBudget_OoeGeneral
join b in db.iBudget_Particulars on a.ParticularID equals b.id
join c in obligationRequestDetailsTotalCostByOoe on a.id equals c.id
join d in totalAllotmentGeneralFund on a.id equals d.id
join e in totalAppropriationGeneralFund on a.id equals e.id
where a.YearID==year && a.ProjectID==cat && a.type==type
orderby a.id
select new
{
id = a.id,
title = b.title,
appro = e.totalAppro,
allo = d.totalAllo,
cost = c.totalCost,
unobligated = c.totalCost==null ? d.totalAllo : d.totalAllo - c.totalCost
}).ToList();
db.iBudget_OoeGeneral and db.iBudget_Particulars are model class in my project
obligationRequestDetailsTotalCostByOoe , totalAllotmentGeneralFund and totalAppropriationGeneralFund are variables with list values.
The question is what is causing this error? I tried looking the web for some answers but none was showing up.
UPDATE
var obligationRequestDetailsTotalCostByOoe = (from p in db.iBudget_ObligationRequestDetails
where p.ooe_general_id != null && p.is_approved == 1
group p by p.ooe_general_id into g
select g)
.AsEnumerable()
.Select(g => new {
id = g.Key,
totalCost = g.Sum(p => Convert.ToDouble(p.amount))
}).ToList();
Originally, obligationRequestDetailsTotalCostByOoe , totalAllotmentGeneralFund and totalAppropriationGeneralFund were Views in SQL Server. Since I was practicing how to code Linq, I didn't create a View and just made a var with list same with the original View Code in SQL.

Converting left outer join on two queries to LINQ

I have below sql query which I want to convert into LINQ to obtain exactly same results and returned by below query
select *
from (
select distinct DocID
from UserViewDoc
where UserViewDoc.UVID in (102558)) a
left outer join
(
select distinct UserViewDoc.DocID
from UserViewDoc
inner join UserViewHeader on UserViewDoc.UVID = UserViewHeader.UVID
where UserViewDoc.UVID not in (102558)
and UserViewHeader.IsLock = 1) b on a.DocID = b.DocID
where b.DocID is null
)
What I have tried so far is below LINQ statement
var v = (from uvd in this.ViewSelectorControl.LDReviewContext.GetTable<UserViewDoc>()
where IDs.Contains(uvd.UVID)
select new { uvd.DocID, uvd.UVID });
var c = ((from uvd in this.ViewSelectorControl.LDReviewContext.GetTable<UserViewDoc>()
join uvh in this.ViewSelectorControl.LDReviewContext.GetTable<UserViewHeader>() on uvd.UVID equals uvh.UVID
where !IDs.Contains(uvh.UVID) && uvh.IsLock == true
select new { uvd.DocID, uvd.UVID } ));
var d = (from id in v
join ids in c on id.UVID equals ids.UVID into vc
from sub in vc.DefaultIfEmpty()
where sub == null
select id);
The problem I am facing is running the SQL query is returning 30583 records and LINQ version of it is returning all of the 30613 records
I rewrote the query to be exactly like the sql query, i believe that this is the way:
var firstQuery = (from u in this.ViewSelectorControl.LDReviewContext.GetTable<UserViewDoc>()
where IDs.Contains(u.UVID)
select u.DocID).Distinct();
var innerQuery = (from u in this.ViewSelectorControl.LDReviewContext.GetTable<UserViewDoc>()
join uvh in this.ViewSelectorControl.LDReviewContext.GetTable<UserViewHeader>() on uvh.UVID equals u.UVID
where IDs.Contains(u.UIVD) == false
&& uvh.IsLock
select u.DocID).Distinct();
var resultQuery = from f in firstQuery
join i in innerQuery on i equals f into lout
from i in lout.DefaultIfEmpty()
where i == null
select f;

Why don't my SQL results match my Linq results?

When I run this Query in SQL I get what I want:
SELECT Auckland_Park.Formative.[Formative Name]
FROM Auckland_Park.LearningUnit
INNER JOIN Auckland_Park.Formative
ON Auckland_Park.LearningUnit.ID = Auckland_Park.Formative.FK_LU
INNER JOIN Auckland_Park.Reference
INNER JOIN Auckland_Park.Course
ON Auckland_Park.Reference.FK_Course = Auckland_Park.Course.ID
ON Auckland_Park.LearningUnit.ID = Auckland_Park.Reference.FK_LU
WHERE Auckland_Park.Course.Name = 'BI'
My result:
Querying SQL Build
Report Develop
Java App Develop
Andriod App Set up
SharePoint Server
But when I work with my C# app I'm using LINQ to SQL, my LINQ Query looks like this:
//LINQ Query to fill Foramtive Name ComboBox
CTUDataContext data = new CTUDataContext();
var course = (from r in data.LearningUnits
join a in data.Formatives
on r.ID equals a.FK_LU
join f in data.References
on r.ID equals f.FK_LU
join g in data.Courses
on f.FK_LU equals g.ID
where g.Name == ("BI")
select new
{
formativeName = a.Formative_Name,
ID = a.ID
}
).ToList();
txtFormativeName.ItemsSource = course;
txtFormativeName.DisplayMemberPath = "formativeName";
txtFormativeName.SelectedValuePath = "ID";
It seems the same, but I'm not getting the same result that I'm getting with the SQL Query above.
//LINQ Query to fill Foramtive Name ComboBox
CTUDataContext data = new CTUDataContext();
var course = (from r in data.LearningUnits
join a in data.Formatives
on r.ID equals a.FK_LU
join f in data.References
on r.ID equals f.FK_LU
join g in data.Courses
on f.FK_LU equals g.ID
where g.Name == ("BI")
select new
{
formativeName = a.Formative_Name,
ID = a.ID
}
).ToList();
txtFormativeName.ItemsSource = course;
txtFormativeName.DisplayMemberPath = "formativeName";
txtFormativeName.SelectedValuePath = "ID";
ANSWER:
on f.FK_LU equals g.ID
f.FK_LU
must be replaced with
f.FK_Course

How to Implement this Sql block contain (Having , Join and Group By) with Linq

my sql statement is
SELECT c.type,c.title,c.datereg, d.ranknum
FROM T_News AS c
INNER JOIN (
SELECT a.id, COUNT(*) AS ranknum
FROM T_News AS a
INNER JOIN T_News AS b
ON (a.type = b.type)
AND (a.datereg >= b.datereg)
GROUP BY a.id
HAVING COUNT(*) <= 3
) AS d ON (c.id = d.id)
ORDER BY c.type, d.ranknum
that i get http://rickosborne.org/blog/2008/01/sql-getting-top-n-rows-for-a-grouped-query/
for Getting TOP N rows for a grouped query
EFUnitOfWork EF = new EFUnitOfWork();
T_NewsRepository News = new T_NewsRepository();
News.UnitOfWork = EF;
var query =
from news1 in News.All()
join news2 in News.All()
on news1.type equals news2.type into resjoin
group news1 by news1.id into idgroup
where idgroup.Count() <= 3
select new { idgroup };
var x = query.ToList();
I did not get any error , but "where idgroup.Count() <= 3" did not work and i get all rows in db as result
Break it down into it's smallest components and then compose the larger query from that. Let's start with the innermost query that makes sense:
SELECT
a.id, COUNT(*) AS ranknum
FROM
T_News AS a
INNER JOIN T_News AS b ON
(a.type = b.type) AND
(a.datereg >= b.datereg)
GROUP BY
a.id
HAVING
COUNT(*) <= 3
I'd convert this to:
// Items with counts/ranknum
var ranknum =
from a in News.All()
join b in News.All() on
a.type equals b.type
where
a.datereg > b.datereg
group by a.id into g
select new { g.Key as id, g.Count() as ranknum };
// Filter the ranknum.
ranknum = ranknum.Where(rn => rn.ranknum <= 3);
Then joining that with the outer query:
SELECT
c.type,c.title,c.datereg, d.ranknum
FROM
T_News AS c
INNER JOIN (<sub-query from above>) as d ON
c.id = d.id
ORDER BY
c.type, d.ranknum
That part becomes simple, as it's just a join between two existing queries.
var query =
from c in News.All()
join rn in ranknum on c.id = rn.id
orderby c.type, rn.ranknum
select new { c.type, c.title, c.datereg, rn.ranknum };
Chances are the SQL that LINQ-to-Entities generates for this is going to look really ugly, and probably be inefficient, in which case, you might want to consider placing this logic in a stored procedure and then calling that through LINQ-to-Entities (which is generally true for more complex queries).

Categories