Complex LINQ-TO-SQL solution.......or just my inexperience? - c#

Learning LINQ-TO-SQL and getting on well. But now I think I'm at a "walk before you run" stage.
This LINQ-TO-SQL works:
var arr = (from up in db.fad_user_physician
join u in db.fad_user on up.userID equals u.userID
where up.physicianID.ToString() == userIdString
select new ListOfUsersForPhysician
{
userID = u.userID,
forename = u.forename,
surname = u.surname,
email = u.email,
gender = u.gender,
dobStr = u.dob.ToString()
}).ToList();
I now want to incorporate a calculation into it.
The TSQL (which works) is thus:
(Note: physicianID is the only thing I have to work with, obtained from their logon details)
EDITED 17/2/16 16:03:
select fuf.userid,
((CAST(COUNT(fuf.userid)AS DECIMAL(6,2))/
(DATEDIFF(dd,fu.dateJoined,GETDATE())*5))*100) AS 'percent'
from fad_user_physician fup
inner join fad_user fu on fu.userID = fup.userID
inner join fad_userFoods fuf on fuf.userID = fu.userID
inner join fad_food ff on ff.foodID = fuf.FoodID
where fup.physicianID = '5C46F531-FF64-4254-8072-F291627ABD3D'
AND fuf.quantityAmount >= ff.portionSize
group by fuf.userID,fu.dateJoined
So basically I want a list of users for a physician, with a % calculation as well.
I've googled this for many an hour, tutorials and all. But just getting bogged down in the complexity of LINQ-TO-SQL (for the newbie!)
Should I be using a LET statement?
Should I be using a LINQ-TO-SQL statement in the select part?
I tried:
let maxPos = DbFunctions.DiffDays(u.dateJoined, DateTime.Now)*5
let temp = (from fuf in db.fad_userFoods
join ff in db.fad_food on fuf.foodID equals ff.foodID
join fu in db.fad_user on fuf.userID equals fu.userID
where fuf.userID.ToString() == userIdString
&& fuf.quantityAmount >= ff.portionSize
group fuf by new {num = fuf.userID} into e
select new {total = e.Key.num}).Count()
maxpos gives me the correct value.
But temp gives me 0.
Any guidance would be appreciated!
Thanks in advance.

You should be able to do the following using navigation properties
var results = from fu in db.fad_user
from fuf in fu.fad_userFoods
from ff in fuf.fad_foods
where fuf.userId = someGuid && fuf.quantityAmount >= ff.portionSize
group fu.userid by new {fuf.userID, fu.dateJoined} into g
select new
{
g.Key.userid,
Percent = 100 * ((decimal)(g.Count())
/ (DbFunctions.DiffDays(g.Key.dateJoined, DateTime.Now) * 5))
};
or using join if you don't have navigation properties
var results = from fu in db.fad_user
join fuf in db.fad_userFoods on fuf.userID equals fu.userID
join ff in db.fad_food on fuf.foodID equals ff.foodID
where fuf.userId = someGuid && fuf.quantityAmount >= ff.portionSize
group fu.userid by new {fuf.userID, fu.dateJoined} into g
select new
{
g.Key.userid,
Percent = 100 * ((decimal)(g.Count())
/ (DbFunctions.DiffDays(g.Key.dateJoined, DateTime.Now) * 5))
};

Related

Converting complex SQL with FULL JOIN to Linq

I am trying to convert a SQL statement to Linq/Entity Framework, and am having a difficult time. Below is the SQL.
SELECT
trust.FName,
trust.MName,
trust.LName
tla.Address,
tma.Address,
at.Descr
FROM CLIENTSSUITS cs
INNER JOIN TRUSTS trust ON trust.SSN = cs.CLIENT
FULL JOIN ADV_TYPES at ON at.CODE = trust.AT
LEFT OUTER JOIN CLIENTADDRESSES tla ON tla.SSN = trust.SSN AND tla.ID = 'L'
LEFT OUTER JOIN CLIENTADDRESSES tma ON tma.SSN = trust.SSN AND tma.ID = 'M'
WHERE cs.PRIMARY = w AND SecondaryRole = x AND cs.ID = y AND cs.Rev = z AND cs.DELETED = 0
GROUP BY trust.FName,
trust.MName,
trust.LName,
tla.Address,
tma.Address,
at.Descr
The FULL JOIN and the GROUP BY seem to be what I'm struggling most with. I've reviewed this SO answer and I understand how to execute a FULL JOIN on its own, but can't figure out how to integrate that into the larger overall query.
TYA for any answers.
Try this
using(var ctx = new Dbcontext())
{
var list = (
from cs in ctx.CLIENTSSUITS
join trust in ctx.TRUSTS on cs.CLIENT equals trust.CLIENT
join at in ctx.ADV_TYPES on at.CODE equals trust.AT into temp from temp.DefaultIfEmpty()
join tla1 in ctx.CLIENTADDRESSES on tla.SSN equals trust.SSN && tla.ID = 'L' into temp2 from subtla1 in temp2.DefaultIfEmpty()
join tla2 in ctx.CLIENTADDRESSES on tla2.SSN equals trust.SSN && tla2.ID = 'M' into temp3 from subtla2 in temp3.DefaultIfEmpty()
where (cs.PRIMARY = w && ?.SecondaryRole = x && cs.ID = y && cs.Rev = z && cs.DELETED = 0)
select new
{
FName = trust.FName,
MName = trust.MName,
LName = trust.LName
LAddress = tla.Address,
MAddress = tma.Address,
Descr = at.Descr
}).ToList();
}
//if the list contains the right result then you can easily group it with this code
var results = list.GroupBy(x => new {
x.FName, x.MName, x.LName, x.LAddress, x.MAddress, Descr
});

LINQ: join multiple Table Column using Linq and find aggregated sum from child table values

I'm using Linq (code-first approach) query to retrieve the data from DB and couldn't able to get similar result while using below linq query:
from msi in db.MainSaleInvoiceTbls
join dsi in db.DetialSaleInvoiceTbls on msi.Id equals dsi.MainSaleInvoiceId
join ca in db.CustomerAccounts on msi.CustomerId equals ca.Id
join cg in db.MiscLists on ca.CustomerGroupId equals cg.Id
where msi.IsActive == true && msi.CompanyId == UniversalInfo.UserCompany.Id && msi.MainSaleInvoiceDataType == MainSaleInvoiceType.SOInvoice
group msi by new { dsi,msi.Date,msi.FinancialVoucher,msi.SaleOrderPrefix,msi.SaleOrderNumber,msi.SalesId,ca.CustomerName,ca.AccountCode,cg.Name }
into mainSaleInvoice
from dx in mainSaleInvoice.DefaultIfEmpty()
// orderby main.Id
select new
{
Date = mainSaleInvoice.Key.Date,
Voucher = mainSaleInvoice.Key.FinancialVoucher,
InvoiceAccount = mainSaleInvoice.Key.AccountCode,
CustomerName = mainSaleInvoice.Key.CustomerName,
CustomerGroup = mainSaleInvoice.Key.Name,
Invoice = mainSaleInvoice.Key.SaleOrderPrefix + mainSaleInvoice.Key.SaleOrderNumber,
PurchaseOrder = mainSaleInvoice.Key.SalesId,
SalesTax = "",
InvoiceAmount = mainSaleInvoice.Sum(x => (Double)(mainSaleInvoice.Key.Quantity * mainSaleInvoice.Key.UnitPrice))
}).ToList()
In linq, i need to get shortdatetimeString() and sum() of (unitprice* quantity) from child table DetialSaleInvoiceTbls
being new in query writing, I don't know where and what I'm doing wrong. Any suggestions would be much appreciated.
var list=from msi in db.MainSaleInvoiceTbls
join dsi in db.DetialSaleInvoiceTbls on msi.Id equals dsi.MainSaleInvoiceId
join ca in db.CustomerAccounts on msi.CustomerId equals ca.Id
join cg in db.MiscLists on ca.CustomerGroupId equals cg.Id into a
where msi.IsActive == true && msi.CompanyId == UniversalInfo.UserCompany.Id
&& msi.MainSaleInvoiceDataType == MainSaleInvoiceType.SOInvoice
from cg in a.DefaultIfEmpty()
select new
{mainSaleInvoice.Date,
mainSaleInvoice.FinancialVoucher,mainSaleInvoice.AccountCode,
mainSaleInvoice.CustomerName,mainSaleInvoice.Name,
mainSaleInvoice.SaleOrderPrefix, mainSaleInvoice.SaleOrderNumber,
mainSaleInvoice.SalesId, }).sum(x=>x. (mainSaleInvoice.Quantity *
mainSaleInvoice.UnitPrice)).groupby msi new
{msi.Date,msi.FinancialVoucher,msi.SaleOrderPrefix,msi.SaleOrderNumber,
msi.SalesId};
Date = mainSaleInvoice.Date;
Voucher = mainSaleInvoice.FinancialVoucher;
InvoiceAccount = mainSaleInvoice.AccountCode;
CustomerName = mainSaleInvoice.CustomerName;
CustomerGroup = mainSaleInvoice.Name;
Invoice = mainSaleInvoice.SaleOrderPrefix +
mainSaleInvoice.SaleOrderNumber;
PurchaseOrder = mainSaleInvoice.SalesId;
SalesTax = "";
InvoiceAmount =list;

T-SQL to LINQ query that has a case statement and a subquery in it

I'm a complete beginner in LINQ and I would like to convert this T-SQL query in LINQ
SELECT
CASE
WHEN D.IsBaseloadDefined = 1
THEN COUNT(D.DeviceID)
ELSE
(SELECT COUNT(DORG.DeviceID)
FROM DeviceOrganization DORG
INNER JOIN Organization ORG ON DORG.OrganizationID = ORG.OrganizationID
INNER JOIN BaseloadOrganization BO ON ORG.BaseloadOrganizationId = BO.OrganizationID
INNER JOIN Baseload BL ON BO.BaseloadID = BL.BaseloadID
WHERE DORG.DeviceID = D.DeviceID
AND BL.RecursUntil >= GETDATE()
GROUP BY DORG.DeviceID)
END AS [Nb of devices]
FROM DeviceOrganization DO
INNER JOIN Device D ON DO.DeviceID = D.DeviceID
LEFT JOIN BaseloadDevice BD ON D.DeviceID = BD.DeviceID
LEFT JOIN Baseload B ON BD.BaseloadID = B.BaseloadID AND B.RecursUntil >= GETDATE()
INNER JOIN OrganizationHierarchy OH ON DO.OrganizationID = OH.SubOrganizationID
WHERE OH.OrganizationID = 6
AND D.IsActive = 1
group by D.DeviceID, D.IsBaseloadDefined
I've seen this topic but I don't really understand the answer
The only thing I could do so far is this, and now I'm completly lost
from deviceO in _context.DeviceOrganizations
join d in _context.Devices on deviceO.DeviceID equals d.DeviceID
join bd in _context.BaseloadDevices on d.DeviceID equals bd.DeviceID
join b in _context.Baseloads on bd.BaseloadID equals b.BaseloadID
join oh in _context.OrganizationHierarchies on deviceO.OrganizationID equals oh.SubOrganizationID
where oh.OrganizationID == OrganizationId
where d.IsActive == true
where b.RecursUntil <= DateTime.Now
group d.DeviceID by d.DeviceID).Count()
Instead of get count of group
group d.DeviceID by d.DeviceID).Count()
you should save result in variable
var data = from deviceO in _context.DeviceOrganizations
join d in _context.Devices on deviceO.DeviceID equals d.DeviceID
join bd in _context.BaseloadDevices on d.DeviceID equals bd.DeviceID
join b in _context.Baseloads on bd.BaseloadID equals b.BaseloadID
join oh in _context.OrganizationHierarchies on deviceO.OrganizationID equals oh.SubOrganizationID
where oh.OrganizationID == OrganizationId
where d.IsActive == true
where b.RecursUntil <= DateTime.Now
and then you should do something like this:
//group by 2 properties
var result = data.GroupBy(d => new { d.DeviceID, d.IsBaseloadDefined })
.Select(g =>
{
//for each group we get IsBaseloadDefined property
var IsBaseloadDefined = g.Key.IsBaseloadDefined;
if (IsBaseloadDefined == 1)
{
return g.Count();
}
else
{
// here another select that return count:
//(SELECT COUNT(DORG.DeviceID)
//FROM DeviceOrganization DORG
// INNER JOIN Organization ORG ON DORG.OrganizationID = ORG.OrganizationID
//INNER JOIN BaseloadOrganization BO ON ORG.BaseloadOrganizationId = BO.OrganizationID
//INNER JOIN Baseload BL ON BO.BaseloadID = BL.BaseloadID
//WHERE DORG.DeviceID = D.DeviceID
//AND BL.RecursUntil >= GETDATE()
//GROUP BY DORG.DeviceID)
//in this query you should return Count() of group
return 1; //return group.Count() instead 1
}
});
I hope this helps you

How do I sum a column in a child table of a projected linq query?

I'm still pretty green on linq when it comes to projection and grouping. How can I get the results of the following SQL query using linq? Or is there a better approach to retrieving this query besides linq? I'm using entity framework and I know I can just hard code the sql but would prefer not to do that if there is a better way.
SELECT j.JobId, j.Name, j.OrderId, j.ShipDate,
st.ShipTypeId, sum(p.DeliveryCnt * p.Quantity) AS 'DeliveryCnt'
FROM Jobs j
JOIN ShipTo st ON j.JobId = st.JobId
JOIN DesignSets ds ON j.JobId = ds.JobId
JOIN DesignSetAreas dsa ON ds.DesignSetId = dsa.DesignSetId
JOIN Products p ON dsa.DesignSetAreaId = p.DesignSetAreaId
WHERE j.ShipDate >= '11/13/2016' AND j.ShipDate <= '11/26/2016'
GROUP BY j.JobId, j.Name, j.OrderId, j.ShipDate, st.ShipTypeId
The below code is what I have so far, but I'm not sure where or how I would do the grouping, or if this is even possible.
var shipList = from j in db.Jobs
join st in db.ShipTo on j.JobId equals st.JobId
join ds in db.DesignSets on j.JobId equals ds.JobId
join p in db.Products on ds.DesignSetId equals p.DesignSetId
where j.ShipDate >= startDate && j.ShipDate <= endDate
select new ShipScheduleViewModel
{
JobId = j.JobId,
Name = j.OrderId + " " + j.Name,
ShipDay = ((DateTime)j.ShipDate).Day,
ShipVia = st.ShipTypeId,
Count = p.DeliveryCnt * p.Quantity
};
Basically the group by syntax requires you to say what you want in the grouping (in this case the p Products are what you are aggregating in the select) and the values you want to group by (in this case the j Job and st.ShipTypeId) and finally you assign the grouping into a variable you can use in your select.
var shipList = from j in db.Jobs
join st in db.ShipTo on j.JobId equals st.JobId
join ds in db.DesignSets on j.JobId equals ds.JobId
join p in db.Products on ds.DesignSetId equals p.DesignSetId
where j.ShipDate >= startDate && j.ShipDate <= endDate
group p by new { j, st.ShipTypeId } into grp
select new ShipScheduleViewModel
{
JobId = grp.Key.j.JobId,
Name = grp.Key.j.OrderId + " " + grp.Key.j.Name,
ShipDay = ((DateTime)grp.Key.j.ShipDate).Day,
ShipVia = grp.Key.ShipTypeId,
Count = grp.Sum(p => p.DeliveryCnt * p.Quantity)
};

Incorrect values after SQL to LINQ convertion

I need to convert following SQL into LINQ
select
app.id,
app.name,
app.version,
s.application,
s.analysis,
s.behaviour,
(select count(ia.id)
from appInstalled ia
JOIN deviceUser ud ON ia.device_id = ud.device_id
where ia.app_id = app.id) as deviceCount,
max(alrt.alert_date)
from application app
left join score s on app.app_md5 = s.md5hash
left join alert alrt on app.id = alrt.app_id
where app.name like '%gpsnav%'
group by device;
This is what I've done so far
var appQuery = (from app in entities.applications
join score in entities.scores on app.app_md5 equals score.md5hash into appScore
join alrt in entities.alerts on app.id equals alrt.app_id into appAlerts
from s in appScore.DefaultIfEmpty()
from a in appAlerts.DefaultIfEmpty()
let deviceCount = (from iapp in entities.appInstalled
join ud in entities.deviceUser on iapp.device_id equals ud.device_id
where iapp.id == app.id
select iapp.id).Count()
where string.IsNullOrEmpty(searchTerm) || app.name.ToLower().Contains(searchTerm.ToLower())
select new
{
AppId = app.id,
AppName = app.name,
AppVersion = app.version,
AppScore = s.application,
Analysis = s.analysis,
Behavior = s.behaviour,
Devices = deviceCount,
AlertDate = a.alert_date
});
var grouped = from a in appQuery
group a by new
{
a.AppId,
a.AppName,
a.AppVersion,
a.AppScore,
a.Analysis,
a.Behavior,
a.Devices,
a.AlertDate
} into g
select new
{
g.Key.AppId,
g.Key.AppName,
g.Key.AppVersion,
g.Key.AppScore,
g.Key.Analysis,
g.Key.Behavior,
g.Key.Devices,
AlertDate = g.Max(x=>x.AlertDate)
};
The above LINQ works but the data is incorrect for Device and AlertDate. What I am missing in here? Also I am not getting max of AlertDate while grouping in LINQ.

Categories